stimulus-controllers

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.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "stimulus-controllers" with this command: npx skills add rolemodel/rolemodel-skills/rolemodel-rolemodel-skills-stimulus-controllers

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?

  1. Verify controller is registered in index.js
  2. Run bin/rails stimulus:manifest:update
  3. Check browser console for errors
  4. Verify data attribute spelling (kebab-case)
  5. Ensure JavaScript is enabled in tests (:js tag)

Targets not found?

  • Check target name in static targets matches HTML
  • Use hasXxxTarget to verify existence before accessing
  • Ensure target element is in controller scope

Related Skills

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

bem-structure

No summary provided by upstream source.

Repository SourceNeeds Review
General

optics-context

No summary provided by upstream source.

Repository SourceNeeds Review
General

routing-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
General

turbo-fetch

No summary provided by upstream source.

Repository SourceNeeds Review