mit einem Klick
better-stimulus
Apply Better Stimulus best practices for writing maintainable, reusable StimulusJS controllers following SOLID principles
Menü
Apply Better Stimulus best practices for writing maintainable, reusable StimulusJS controllers following SOLID principles
| name | better-stimulus |
| description | Apply Better Stimulus best practices for writing maintainable, reusable StimulusJS controllers following SOLID principles |
Apply opinionated best practices from betterstimulus.com when writing or refactoring Stimulus controllers. These patterns emphasize code reusability, proper separation of concerns, and SOLID design principles.
Invoke this skill when:
Externalize hardcoded values into data attributes rather than embedding them in controller logic.
Bad:
toggle() {
this.element.classList.toggle("active")
}
Good:
static classes = ["active"]
toggle() {
this.element.classList.toggle(this.activeClass)
}
<div data-controller="toggle" data-toggle-active-class="active"></div>
Store controller state in Stimulus values, not instance properties, to leverage reactivity and DOM persistence.
Bad:
connect() {
this.count = 0
}
Good:
static values = { count: Number }
countValueChanged(count) {
this.updateDisplay()
}
Each controller should have one reason to change. Split controllers that mix concerns.
Ask: "What would cause this controller to change?" If multiple unrelated reasons, split it.
Use connect() for:
Don't use connect() for:
data-action)Use data-action attributes instead of addEventListener() to let Stimulus manage lifecycle.
Bad:
connect() {
document.addEventListener("click", this.handler.bind(this))
}
Good:
<div data-action="click@document->controller#handler"></div>
See: references/architecture.md
[name]ValueChanged)See: references/state-management.md
connect() for third-party library initializationconnect() with disconnect() for cleanupconnect() with state setupteardown() for Turbo-specific cleanupSee: references/lifecycle.md
Three approaches:
Choose based on relationship:
See: references/events-and-interaction.md
See: references/solid-principles.md
<template> to restore DOM staterequestSubmit() not submit() for formsSee: references/dom-and-turbo.md
handleError() methodSee: references/error-handling.md
static values = {
url: String,
count: Number,
enabled: Boolean,
items: Array,
config: Object
}
<!-- Element events -->
<div data-action="click->controller#method">
<!-- Global events -->
<div data-action="resize@window->controller#layout">
<div data-action="keydown@document->controller#handleKey">
<!-- Multiple actions -->
<div data-action="click->ctrl1#method1 click->ctrl2#method2">
// Dispatch
const event = new CustomEvent('name:action', {
bubbles: true,
detail: { key: 'value' }
})
this.element.dispatchEvent(event)
// Listen
data-action="name:action->controller#handler"
<div data-controller="parent"
data-parent-child-outlet=".child">
<div class="child" data-controller="child"></div>
</div>
static outlets = ['child']
this.childOutlets.forEach(outlet => outlet.method())
connect() // Element connected to DOM
disconnect() // Element removed from DOM
[name]TargetConnected(element) // Target added
[name]TargetDisconnected(element) // Target removed
[name]ValueChanged(value, oldValue) // Value changed
[name]OutletConnected(outlet) // Outlet connected
[name]OutletDisconnected(outlet) // Outlet disconnected
When writing a new controller:
When refactoring:
connect() with state setup and event listenersaddEventListener() without proper cleanup.bind() separately in connect and disconnectsubmit() instead of requestSubmit()All patterns in this skill come from betterstimulus.com, an opinionated collection of StimulusJS best practices.
For detailed explanations and examples, see:
references/architecture.md - Controller design patternsreferences/state-management.md - Values API usagereferences/lifecycle.md - Lifecycle best practicesreferences/events-and-interaction.md - Communication patternsreferences/solid-principles.md - SOLID design principlesreferences/dom-and-turbo.md - DOM manipulation and Turboreferences/error-handling.md - Error managementAdd polymorphic activity timelines with live Turbo Stream updates to any Rails model. Covers migration, model, concern, shared partials, broadcasting, and optional AI-generated change summaries.
Add Tiptap rich text editing with debounced autosave to Rails models using Stimulus. Stores markdown in text columns (not ActionText). Covers installation, Stimulus controller, shared partials, Turbo cache handling, and optional change tracking.
Implement MCP server authentication with OAuth Dynamic Client Registration (RFC 7591), Authorization Server Metadata Discovery (RFC 8414), and generalized per-agent credential support. This skill should be used when building admin UIs that let users connect to third-party MCP servers, whether they use OAuth (Linear, Sentry, Granola), bearer tokens (Render, custom APIs), or API keys. Covers the full flow: metadata discovery, client registration, PKCE authorization, token exchange, token refresh, tool sync, and credential storage patterns (shared vs per-agent for any auth type). Includes hard-won lessons from production implementation.