> hotwire
You are an expert in Hotwire (HTML Over The Wire), the collection of techniques for building modern web applications by sending HTML instead of JSON. You help developers use Turbo (Drive, Frames, Streams) for SPA-like navigation and partial updates, and Stimulus for lightweight JavaScript behavior — building fast, server-rendered applications that feel like SPAs with minimal client-side JavaScript.
curl "https://skillshub.wtf/TerminalSkills/skills/hotwire?format=md"Hotwire — HTML Over the Wire
You are an expert in Hotwire (HTML Over The Wire), the collection of techniques for building modern web applications by sending HTML instead of JSON. You help developers use Turbo (Drive, Frames, Streams) for SPA-like navigation and partial updates, and Stimulus for lightweight JavaScript behavior — building fast, server-rendered applications that feel like SPAs with minimal client-side JavaScript.
Core Capabilities
Turbo Drive (SPA-like navigation)
<!-- Turbo Drive is automatic — no configuration needed -->
<!-- All link clicks and form submissions are intercepted -->
<!-- Only the <body> is replaced; <head> assets are preserved -->
<!-- Opt out specific links -->
<a href="/external" data-turbo="false">External Link</a>
<!-- Prefetch on hover for instant navigation -->
<a href="/dashboard" data-turbo-prefetch="true">Dashboard</a>
<!-- Progress bar appears automatically during navigation -->
<style>
.turbo-progress-bar {
background-color: #6366f1;
height: 3px;
}
</style>
Turbo Frames (partial page updates)
<!-- Only the content inside matching turbo-frame is replaced -->
<turbo-frame id="messages">
<h2>Messages</h2>
<div class="message-list">
<!-- Messages rendered server-side -->
<div class="message">Hello from server!</div>
</div>
<!-- This link only updates THIS frame -->
<a href="/messages?page=2">Load more</a>
</turbo-frame>
<!-- Lazy-loaded frame (loads on page appear) -->
<turbo-frame id="notifications" src="/notifications" loading="lazy">
<p>Loading notifications...</p>
</turbo-frame>
<!-- Frame that targets another frame -->
<turbo-frame id="sidebar">
<a href="/users/42" data-turbo-frame="main-content">View Profile</a>
</turbo-frame>
<turbo-frame id="main-content">
<!-- Profile loads here -->
</turbo-frame>
Turbo Streams (real-time updates)
<!-- Server sends these HTML snippets to update the page -->
<!-- Via form response, WebSocket, or SSE -->
<!-- Append a new message to the list -->
<turbo-stream action="append" target="messages">
<template>
<div id="message_42" class="message">
<strong>Alice:</strong> New message just arrived!
</div>
</template>
</turbo-stream>
<!-- Replace an existing element -->
<turbo-stream action="replace" target="message_42">
<template>
<div id="message_42" class="message edited">
<strong>Alice:</strong> Edited message content
</div>
</template>
</turbo-stream>
<!-- Remove an element -->
<turbo-stream action="remove" target="message_42"></turbo-stream>
<!-- Update element content (keep the wrapper) -->
<turbo-stream action="update" target="unread-count">
<template>5</template>
</turbo-stream>
<!-- Available actions: append, prepend, replace, update, remove, before, after -->
Stimulus (lightweight JS behavior)
// src/controllers/dropdown_controller.js
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static targets = ["menu"]; // data-dropdown-target="menu"
static values = { open: Boolean }; // data-dropdown-open-value="false"
static classes = ["active"]; // data-dropdown-active-class="opacity-100"
toggle() {
this.openValue = !this.openValue;
}
openValueChanged() {
this.menuTarget.classList.toggle(this.activeClass, this.openValue);
this.menuTarget.classList.toggle("hidden", !this.openValue);
}
// Close on click outside
close(event) {
if (!this.element.contains(event.target)) {
this.openValue = false;
}
}
}
<!-- HTML with Stimulus controller -->
<div data-controller="dropdown"
data-dropdown-active-class="opacity-100"
data-action="click@window->dropdown#close">
<button data-action="dropdown#toggle">Menu ▾</button>
<ul data-dropdown-target="menu" class="hidden">
<li><a href="/profile">Profile</a></li>
<li><a href="/settings">Settings</a></li>
<li><a href="/logout">Logout</a></li>
</ul>
</div>
Installation
# With import maps (Rails 7+, no bundler)
bin/importmap pin @hotwired/turbo @hotwired/stimulus
# With npm
npm install @hotwired/turbo @hotwired/stimulus
# JavaScript setup
import * as Turbo from "@hotwired/turbo";
import { Application } from "@hotwired/stimulus";
const application = Application.start();
Best Practices
- Server-first — Render HTML on the server; Turbo handles making it feel like an SPA
- Frames for partials — Use Turbo Frames to update sections independently; no full-page reloads needed
- Streams for real-time — Use Turbo Streams over WebSocket/SSE for live updates (chat, notifications, dashboards)
- Stimulus for behavior — Only add JS for interactive behavior (dropdowns, modals, form validation); not for rendering
- Minimal JavaScript — A typical Hotwire app has 10-20 small Stimulus controllers vs. 500+ React components
- Progressive enhancement — Everything works without JavaScript; Turbo enhances with speed, Stimulus adds behavior
- Works with any backend — Designed for Rails but works with Django, Laravel, Express, Go — any server that renders HTML
- Cache effectively — Turbo caches pages; use
data-turbo-cache="false"on pages that should never be cached
> related_skills --same-repo
> zustand
You are an expert in Zustand, the small, fast, and scalable state management library for React. You help developers manage global state without boilerplate using Zustand's hook-based stores, selectors for performance, middleware (persist, devtools, immer), computed values, and async actions — replacing Redux complexity with a simple, un-opinionated API in under 1KB.
> zoho
Integrate and automate Zoho products. Use when a user asks to work with Zoho CRM, Zoho Books, Zoho Desk, Zoho Projects, Zoho Mail, or Zoho Creator, build custom integrations via Zoho APIs, automate workflows with Deluge scripting, sync data between Zoho apps and external systems, manage leads and deals, automate invoicing, build custom Zoho Creator apps, set up webhooks, or manage Zoho organization settings. Covers Zoho CRM, Books, Desk, Projects, Creator, and cross-product integrations.
> zod
You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.
> zipkin
Deploy and configure Zipkin for distributed tracing and request flow visualization. Use when a user needs to set up trace collection, instrument Java/Spring or other services with Zipkin, analyze service dependencies, or configure storage backends for trace data.