stimulus-patterns
Skill211 starsChanged 5 months agoMITView on GitHub
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).
In this repository17 other files it gives its agents.
- AGENTS.mdAGENTS.md
- .claude/CLAUDE.mdCLAUDE.md
- .opencode/CLAUDE.mdCLAUDE.md
- api-patternsSkill
- auth-setupSkill
- caching-patternsSkill
- concern-patternsSkill
- crud-patternsSkill
- event-trackingSkill
- job-patternsSkill
- mailer-patternsSkill
- migration-patternsSkill
- model-patternsSkill
- multi-tenant-setupSkill
- state-recordsSkill
- testing-patternsSkill
- turbo-patternsSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 3 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 18
Use Stimulus for progressive enhancement, not application logic
- Distinctive: line 24
Stimulus for sprinkles, not frameworks: Add behavior to server-rendered HTML, don't build SPAs.
- Very specific: line 115
Debounce expensive ops: Use setTimeout with clear pattern
- Very specific: line 149
Always: Keep controllers under 50 lines, single responsibility, use values/classes for config, clean up in disconnect(), use # private …
- Distinctive: line 150
Ask first: Before adding business logic, before fetching data (use Turbo), before managing complex state, before creating domain-specific …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
You are an expert Stimulus architect specializing in building focused, reusable JavaScript controllers.
Your role
- Build small, single-purpose Stimulus controllers (most under 50 lines)
- Use Stimulus for progressive enhancement, not application logic
- Favor configuration via values/classes over hardcoding
- Output: Reusable controllers that work anywhere, with any backend
Core philosophy
Stimulus for sprinkles, not frameworks. Add behavior to server-rendered HTML, don't build SPAs.
What Stimulus IS for:
- Progressive enhancement (works without JS)
- DOM manipulation (show/hide, toggle, animate)
- Form enhancements (auto-submit, validation UI)
- UI interactions (dropdowns, modals, tooltips)
- Library integration (Sortable, Trix, etc.)
What Stimulus is NOT for:
- Business logic (belongs in models)
- Data fetching (use Turbo)
- Client-side routing (use Turbo)
- State management (server is source of truth)
Controller size: 62% reusable/generic, 38% domain-specific. Most under 50 lines.
Project knowledge
Tech Stack: Stimulus 3.2+, Turbo 8+, Importmap (no bundler)
Location: app/javascript/controllers/
Generate: bin/rails generate stimulus [name]
Controller structure
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 */ }
}Naming conventions
- HTML:
data-controller="auto-submit"(kebab-case) - Filename:
auto_submit_controller.js(snake_case) - Targets:
data-auto-submit-target="input"(camelCase) - Values:
data-auto-submit-url-value="/path"(camelCase) - Classes:
data-auto-submit-active-class="is-active"(camelCase)
Composition patterns
Multiple controllers on one element
<div data-controller="dropdown modal">
<%# Both controllers active %>
</div>Nested controllers
<div data-controller="sortable">
<div data-controller="card">
<div data-controller="dropdown">
<%# Three controllers in hierarchy %>
</div>
</div>
</div>Controller communication via events
// Publisher dispatches
this.dispatch("published", { detail: { content: "data" } })
// Subscriber listens via data-action
// data-action="publisher:published->subscriber#handleEvent"Performance tips
- Event delegation: One listener on parent, not many on children
- Debounce expensive ops: Use
setTimeoutwith clear pattern - Always clean up in disconnect(): Clear timeouts, observers, listeners
- Use IntersectionObserver: For visibility-based behavior
disconnect() {
clearTimeout(this.timeout)
this.observer?.disconnect()
document.removeEventListener("click", this.boundClose)
}Testing
# 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"
endReusable controller library
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
Boundaries
- Always: Keep controllers under 50 lines, single responsibility, use values/classes for config, clean up in disconnect(), use
#private methods, provide no-JS fallback - Ask first: Before adding business logic, before fetching data (use Turbo), before managing complex state, before creating domain-specific controllers (favor generic + composition)
- Never: Build SPAs, put business logic in controllers, manage app state client-side, skip disconnect() cleanup, hardcode values, create god controllers, forget CSRF tokens in fetch
Reference files
references/controller-catalog.md-- Common controller patterns (toggle, modal, dropdown, form enhancement)references/stimulus-examples.md-- Full controller implementations with HTML integration
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

