Overview

Stimulus is a JavaScript framework designed to enhance existing HTML with interactive behavior. Unlike traditional single-page application (SPA) frameworks that manage the entire UI lifecycle, Stimulus operates by observing changes in the DOM and connecting JavaScript objects (controllers) to HTML elements using data attributes. This approach allows developers to add dynamic features to server-rendered applications without the overhead or complexity of a full-fledged client-side framework.

Developed by Basecamp, Stimulus is part of the Hotwire set of technologies, which aims to provide a modern, reactive web experience primarily through server-side rendering and minimal JavaScript. It is particularly well-suited for applications built with frameworks like Ruby on Rails, where much of the HTML is generated on the server. Stimulus encourages a clear separation of concerns, keeping JavaScript logic focused on specific DOM elements and their interactions, rather than managing global application state or complex routing.

Developers choose Stimulus when they need to add interactivity, such as dynamic forms, real-time updates, or interactive components, without fully transitioning to a client-side rendering model. It excels in scenarios where the application's core navigation and data fetching are handled by the server, and JavaScript is used to sprinkle in enhancements. The framework's small API surface and convention-over-configuration philosophy contribute to a developer experience that emphasizes simplicity and ease of integration. This makes it accessible for teams who want to gradually introduce more interactivity into their web applications while maintaining a server-centric architecture.

The core concept of Stimulus revolves around "controllers" and "actions." A controller is a JavaScript class that defines behavior, and it is connected to an HTML element using a data-controller attribute. Actions are methods within these controllers that are triggered by DOM events, specified using data-action attributes. This declarative approach allows developers to see which JavaScript behavior is attached to which HTML element directly in the markup, improving maintainability and readability. The framework automatically connects and disconnects controllers as elements appear and disappear from the DOM, simplifying resource management.

For example, a common use case might involve a search bar that filters results dynamically. With Stimulus, the search input and the results container could be associated with a single controller. When the user types, an action on the input triggers a method in the controller, which then updates the results displayed in the container. This pattern minimizes the need for manual DOM manipulation and event listeners, abstracting these common tasks into a structured framework. The Stimulus approach contrasts with other frameworks that might require a virtual DOM or extensive build steps, making it a viable option for projects that prefer a lighter JavaScript footprint and direct manipulation of the actual DOM.

Key features

  • Controllers: Reusable JavaScript classes that encapsulate specific behaviors and are connected to HTML elements via data-controller attributes.
  • Actions: Methods within controllers that respond to DOM events (e.g., click, submit, keyup), defined using data-action attributes on HTML elements.
  • Targets: References to specific child elements within a controller's scope, allowing controllers to easily access and manipulate parts of their managed HTML. Declared with data-target attributes and accessed via this.targetNameTarget in the controller.
  • Values: Declarative way to pass configuration data from HTML to JavaScript controllers, using data-value attributes. These values can be observed for changes within the controller.
  • Lifecycle Callbacks: Methods like initialize, connect, and disconnect that automatically run when a controller is added to or removed from the DOM, enabling proper setup and cleanup.
  • DOM Observation: Stimulus automatically observes the DOM for changes, connecting and disconnecting controllers as elements are added or removed, ensuring behavior is consistently applied.
  • Modest JavaScript Layer: Designed to work alongside server-rendered HTML, providing interactivity without requiring a full client-side application architecture.

Pricing

Stimulus is an open-source JavaScript framework released under the MIT License. There are no direct costs associated with its use, distribution, or modification. Users can download and integrate Stimulus into their projects without licensing fees.

Feature Cost Details
Framework License Free Open-source under MIT License
Commercial Support Varies Not offered directly by Basecamp; available from third-party consultants
Hosting & Deployment Varies Standard web hosting costs apply (not specific to Stimulus)

Pricing as of May 2026

Common integrations

  • Ruby on Rails: Stimulus is part of the Hotwire ecosystem, which originated from Basecamp, the creators of Ruby on Rails. It integrates seamlessly with Rails applications, enhancing server-rendered views with client-side interactivity. The official documentation often features examples using Rails.
  • Turbo (Turbo Drive, Turbo Frames, Turbo Streams): As a core component of Hotwire, Stimulus works in conjunction with Turbo to deliver fast, SPA-like experiences without writing extensive JavaScript. Turbo handles page navigation and partial updates, while Stimulus adds specific interactive behaviors to the elements within those updates. Detailed integration guides are available in the Turbo Handbook.
  • Webpack/Vite/Esbuild: Stimulus can be bundled and optimized using modern JavaScript build tools like Webpack, Vite, or Esbuild. These tools handle module resolution and asset compilation, allowing Stimulus controllers to be written using ES modules and integrated into larger projects.
  • Tailwind CSS: While not a direct integration, Stimulus is often used alongside utility-first CSS frameworks like Tailwind CSS. Stimulus manages behavior, and Tailwind CSS handles styling, providing a complete solution for building user interfaces.
  • Any server-rendered framework: Stimulus is framework-agnostic on the backend and can be integrated with any server-side rendering technology that produces HTML, including PHP, Python, Node.js, and .NET applications.

Alternatives

  • React: A JavaScript library for building user interfaces, primarily focused on component-based architecture and virtual DOM for efficient updates.
  • Vue.js: A progressive JavaScript framework for building user interfaces, known for its approachability and flexible component model.
  • Alpine.js: A lightweight JavaScript framework that offers a declarative approach to add interactivity directly in HTML, similar to Stimulus but with a different syntax and scope.
  • jQuery: A fast, small, and feature-rich JavaScript library that simplifies HTML document traversal and manipulation, event handling, animation, and Ajax.
  • HTMX: A library that allows you to access modern browser features directly from HTML, enabling dynamic interfaces without writing much JavaScript.

Getting started

To get started with Stimulus, you typically install it via npm or yarn and then initialize your application. The following example demonstrates a simple counter controller:

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Stimulus Counter</title>
  <script type="module" src="./index.js"></script>
</head>
<body>
  <div data-controller="counter">
    <h1>Count: <span data-counter-target="count">0</span></h1>
    <button data-action="click->counter#increment">Increment</button>
    <button data-action="click->counter#decrement">Decrement</button>
  </div>
</body>
</html>
// index.js
import { Application, Controller } from '@hotwired/stimulus';

// Initialize Stimulus application
window.Stimulus = Application.start();

// Define a Stimulus controller
class CounterController extends Controller {
  static targets = ["count"];
  static values = { initial: { type: Number, default: 0 } };

  connect() {
    this.count = this.initialValue;
    this.updateCount();
  }

  increment() {
    this.count++;
    this.updateCount();
  }

  decrement() {
    this.count--;
    this.updateCount();
  }

  updateCount() {
    this.countTarget.textContent = this.count;
  }
}

// Register the controller with Stimulus
Stimulus.register("counter", CounterController);

This example sets up a basic counter. The <div data-controller="counter"> element activates the CounterController. The <span data-counter-target="count"> element is accessible within the controller as this.countTarget. Buttons with data-action="click->counter#increment" and data-action="click->counter#decrement" trigger the respective methods in the controller when clicked. The connect() lifecycle method initializes the count, and updateCount() updates the display. More detailed guides and advanced concepts are available in the Stimulus Handbook.