.claude_37signals/skills/stimulus-patterns/SKILL.md
Builds focused, single-purpose Stimulus controllers for progressive enhancement. Use when adding JavaScript behavior, UI interactions, form enhancements, or building reusable client-side components. WHEN NOT: For Turbo Stream/Frame patterns (see turbo-patterns skill). For server-side view logic (see rules/views.md).
npx skillsauth add ThibautBaissac/rails_ai_agents stimulus-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are an expert Stimulus architect specializing in building focused, reusable JavaScript controllers.
Stimulus for sprinkles, not frameworks. Add behavior to server-rendered HTML, don't build SPAs.
Tech Stack: Stimulus 3.2+, Turbo 8+, Importmap (no bundler)
Location: app/javascript/controllers/
Generate: bin/rails generate stimulus [name]
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["input", "output"]
static classes = ["active", "hidden"]
static values = {
url: String,
timeout: { type: Number, default: 5000 }
}
connect() { /* Setup */ }
disconnect() { /* Cleanup -- always clean up! */ }
actionMethod(event) {
event.preventDefault()
this.element.classList.toggle(this.activeClass)
}
#privateHelper() { /* Use # prefix */ }
}
data-controller="auto-submit" (kebab-case)auto_submit_controller.js (snake_case)data-auto-submit-target="input" (camelCase)data-auto-submit-url-value="/path" (camelCase)data-auto-submit-active-class="is-active" (camelCase)<div data-controller="dropdown modal">
<%# Both controllers active %>
</div>
<div data-controller="sortable">
<div data-controller="card">
<div data-controller="dropdown">
<%# Three controllers in hierarchy %>
</div>
</div>
</div>
// Publisher dispatches
this.dispatch("published", { detail: { content: "data" } })
// Subscriber listens via data-action
// data-action="publisher:published->subscriber#handleEvent"
setTimeout with clear patterndisconnect() {
clearTimeout(this.timeout)
this.observer?.disconnect()
document.removeEventListener("click", this.boundClose)
}
# System tests are the primary way to test Stimulus controllers
test "toggle card details" do
visit card_path(cards(:logo))
assert_no_selector ".card__details"
click_button "Show Details"
assert_selector ".card__details"
end
UI: toggle, dropdown, modal, tabs, tooltip Forms: auto-submit, character-counter, form-validation, password-visibility Utility: clipboard, auto-dismiss, confirm, disable Integration: sortable, trix, flatpickr Tracking: beacon, visibility, scroll
# private methods, provide no-JS fallbackreferences/controller-catalog.md -- Common controller patterns (toggle, modal, dropdown, form enhancement)references/stimulus-examples.md -- Full controller implementations with HTML integrationdevelopment
Creates Turbo Streams, Turbo Frames, and morphing patterns for real-time UI updates. Use when adding real-time updates, partial page rendering, form submissions, or broadcasting. WHEN NOT: For Stimulus JavaScript controllers (see stimulus-patterns skill). For general view conventions (see rules/views.md).
testing
Writes Minitest tests with fixtures following 37signals conventions. Uses Minitest (not RSpec) and fixtures (not factories). Use when writing tests, adding test coverage, or creating fixtures. WHEN NOT: For RSpec or FactoryBot patterns (this project uses Minitest + fixtures exclusively). For test configuration/CI setup (see project docs).
testing
Implements the state-as-records-not-booleans pattern for rich state tracking. Use when modeling state changes, replacing boolean flags with record-based state, or when user mentions state records, closures, publications, or toggling state. WHEN NOT: Technical flags like cached/processed (use booleans), concern extraction (use concern-patterns), general model work (use model-patterns).
data-ai
Implements URL-based multi-tenancy with account scoping, membership patterns, and data isolation following 37signals patterns. Use when setting up multi-tenant architecture, account isolation, membership management, or when user mentions multi-tenancy, accounts, or tenant separation. WHEN NOT: For basic model setup without tenancy (use model-patterns), for auth/session setup (use auth-setup).