Values, Classes, Lifecycle & Hotwire
Typed Values
export default class extends Controller {
static values = { count: Number, active: Boolean }
countValueChanged(newValue) {
console.log('count is now', newValue)
}
}Reads/writes data-[controller]-count-value with automatic type coercion, plus an optional changed callback — no manual parseInt()/JSON.parse(). Because the value lives in the DOM, a Turbo-driven HTML update naturally keeps the controller in sync with zero extra wiring.
Classes — Decoupling CSS from Behavior
static classes = ["active"]
toggle() { this.element.classList.toggle(this.activeClass) }
// reads data-[controller]-active-class instead of hardcoding a class nameLifecycle
connect() { /* element entered the DOM — init here */ }
disconnect() { /* element removed — clean up listeners/timers here */ }Important with Turbo, since page content can be swapped without a full reload — disconnect() is the cleanup hook when a controller's element disappears.
Hotwire: Turbo + Stimulus
Turbo Streams let the server send an HTML fragment that swaps into a specific part of the page — no full reload, no client-owned state model. Stimulus then handles remaining small interactive behavior on that fragment. Tradeoff: great for sprinkled interactivity on mostly server-rendered apps; a full SPA framework is often a better fit for deeply interdependent client-side state (a rich dashboard, a collaborative editor).
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free