name: stimulus-controllers description: Create and register Stimulus controllers for interactive JavaScript features. Use when adding client-side interactivity, dynamic UI updates, or when the user mentions Stimulus controllers or JavaScript behavior.
Stimulus Controllers
Overview
Stimulus controllers provide modular JavaScript functionality connected to HTML via data attributes. After creating a new controller, you must register it in the index.js file.
Creating a New Controller
1. Create the Controller File
Create a new controller in app/javascript/controllers/:
// app/javascript/controllers/example_controller.js
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["element"]
static values = { name: String }
connect() {
// Called when controller is connected to DOM
}
disconnect() {
// Called when controller is disconnected from DOM
}
// Action methods
handleClick(event) {
event.preventDefault()
// Your logic here
}
}
2. Register the Controller
CRITICAL: After creating a new controller, run:
bin/rails stimulus:manifest:update
This automatically updates app/javascript/controllers/index.js to register your controller.
Manual Registration (if needed):
import ExampleController from "./example_controller"
application.register("example", ExampleController)
Controller name in HTML uses kebab-case: data-controller="example"
3. Use in HTML
Connect the controller to HTML elements:
.container data-controller="example" data-example-name-value="test"
button data-action="click->example#handleClick" Click Me
div data-example-target="element" Target Element
Naming Conventions
- File:
example_controller.js(snake_case) - Class:
export default class extends Controller - Registration:
"example"(kebab-case) - HTML:
data-controller="example"(kebab-case) - Multi-word:
bulk_submit_controller.js→"bulk-submit"
Key Concepts
Targets
Reference specific DOM elements:
static targets = ["input", "output"]
// Access in methods:
this.inputTarget // First matching element
this.inputTargets // All matching elements
this.hasInputTarget // Boolean check
Values
Type-safe data attributes:
static values = {
url: String,
count: Number,
active: Boolean,
items: Array,
config: Object
}
// Access in methods:
this.urlValue
this.countValue
// Watch for changes:
urlValueChanged(newUrl, oldUrl) {
// Called when value changes
}
Actions
Connect events to methods:
<!-- Basic action -->
data-action="click->example#save"
<!-- Multiple actions -->
data-action="click->example#save submit->example#submit"
<!-- Custom events -->
data-action="example:refresh->example#reload"
<!-- Event modifiers -->
data-action="submit->example#save:prevent"
Classes
Manage CSS classes:
static classes = ["active", "hidden"]
// Use in methods:
this.element.classList.add(this.activeClass)
this.element.classList.remove(this.hiddenClass)
Common Patterns
Form Validation
export default class extends Controller {
static targets = ["form", "submit"]
validate() {
const isValid = this.formTarget.checkValidity()
this.submitTarget.disabled = !isValid
}
}
Toggle Visibility
export default class extends Controller {
static targets = ["content"]
static classes = ["hidden"]
toggle() {
this.contentTarget.classList.toggle(this.hiddenClass)
}
}
AJAX Updates
export default class extends Controller {
static values = { url: String }
async refresh() {
const response = await fetch(this.urlValue)
const html = await response.text()
this.element.innerHTML = html
}
}
Testing
Test Stimulus controllers in system specs:
it 'handles interaction', :js do
visit page_path
click_button 'Toggle'
expect(page).to have_css('[data-controller="example"]')
end
Troubleshooting
Controller not working?
- Verify controller is registered in
index.js - Run
bin/rails stimulus:manifest:update - Check browser console for errors
- Verify data attribute spelling (kebab-case)
- Ensure JavaScript is enabled in tests (
:jstag)
Targets not found?
- Check target name in
static targetsmatches HTML - Use
hasXxxTargetto verify existence before accessing - Ensure target element is in controller scope
Related Skills
- frontend-patterns - HTML and CSS patterns
- turbo-fetch - Dynamic form updates
- testing-patterns - Testing JavaScript features