--- name: stimulus description: Best practices for using Stimulus controllers to add JavaScript behavior to HTML --- # Stimulus Best Practices for Rails Applications Rule updated on 12/15/2025 to Stimulus version 3.2.2 Stimulus is a modest JavaScript framework designed to augment your HTML with just enough behavior. It connects JavaScript to the DOM via data attributes, keeping your HTML as the source of truth. For full reference see [https://stimulus.hotwired.dev/](https://stimulus.hotwired.dev/) ## Core Concepts | Concept | Purpose | Data Attribute | | ---------- | ---------------------------------------- | ---------------------------------- | | Controller | JavaScript class that adds behavior | `data-controller="name"` | | Target | Important elements referenced in JS | `data-name-target="targetName"` | | Action | Event handlers connecting DOM to methods | `data-action="event->name#method"` | | Value | Reactive data stored in HTML | `data-name-value-name="value"` | | Class | CSS classes toggled by the controller | `data-name-class-name="class"` | | Outlet | References to other controllers | `data-name-outlet-name="selector"` | --- ## When to Use Stimulus **Use Stimulus for:** - Toggle visibility (dropdowns, modals, accordions) - Form enhancements (character counters, auto-submit, validation UI) - Copy to clipboard - Keyboard shortcuts - Animations and transitions - Client-side filtering/sorting (small datasets) - Debounced input handlers - Any behavior that doesn't require server data **Don't use Stimulus for:** - Data that should come from the server (use Turbo Streams instead) - Complex state management (consider if your approach is right) - Things Turbo already handles (form submission, navigation) --- ## Controller Structure ### File Naming & Location Controllers that live in `app/javascript/controllers/` and follow the naming convention below are automatically registered. | File Name | Controller Name | HTML Reference | | ------------------------- | --------------------- | ----------------------------- | | `hello_controller.js` | `HelloController` | `data-controller="hello"` | | `clipboard_controller.js` | `ClipboardController` | `data-controller="clipboard"` | | `user_form_controller.js` | `UserFormController` | `data-controller="user-form"` | ### Basic Controller Template ```javascript import { Controller } from "@hotwired/stimulus" export default class extends Controller { static targets = ["input", "output"] static values = { url: String, count: Number, active: Boolean } static classes = ["hidden", "active"] connect() { // Called when controller is connected to DOM } disconnect() { // Called when controller is removed from DOM // Clean up event listeners, timers, etc. } // Action methods toggle() { this.outputTarget.classList.toggle(this.hiddenClass) } } ``` --- ## Targets Targets provide named references to important elements within the controller's scope. ### Defining Targets ```javascript export default class extends Controller { static targets = ["input", "submit", "error"] validate() { if (this.inputTarget.value.length < 3) { this.errorTarget.textContent = "Too short" this.submitTarget.disabled = true } } } ``` ### HTML Usage ```erb