ai/skills/better-stimulus/SKILL.md
Apply Better Stimulus best practices for writing maintainable, reusable StimulusJS controllers following SOLID principles
npx skillsauth add steveclarke/dotfiles better-stimulusInstall 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.
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 managementcontent-media
Download content from YouTube including transcripts, captions, subtitles, music, MP3s, and playlists. Use when the user provides a YouTube URL or asks to download, transcribe, or get content from YouTube videos or playlists.
development
Apply VueUse composables where appropriate to build concise, maintainable Vue.js / Nuxt features.
development
Review UI for visual consistency, layout structure, and design system compliance. Two modes — code review (check view files against patterns) and visual audit (screenshot all routes and analyze). Use when reviewing UI code, checking consistency, auditing views, or when user says "review the UI", "check consistency", "UI audit", "design review".
tools
Improves typography by fixing font choices, hierarchy, sizing, weight, and readability so text feels intentional. Use when the user mentions fonts, type, readability, text hierarchy, sizing looks off, or wants more polished, intentional typography.