Optimistic Toggle
shadcn-htmx/optimistic-toggleFreeComponent
A server-backed action toggle (like, star, follow, pin) that flips appearance instantly via a native <template> of the toggled state, then reconciles with the server's HTML response — rolling back automatically on error. Built on a real <button> with aria-pressed and the htmx v4 hx-optimistic extension. Ships in five flavours: Hono JSX (TypeScript), Jinja2 macro, Go html/template, Phoenix function component, and a raw HTML snippet. Follows the WAI-ARIA APG button (toggle) pattern.
Live preview
live · rendered by the registry
Rendered by shadcn-htmx on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://shadcn-htmx.productdevbook.com/r/optimistic-toggle.jsonSource
1/** @jsxImportSource hono/jsx */2import type { Child } from "hono/jsx"3import { cn, type ClassValue } from "@/registry/lib/cn"45// Optimistic Toggle — shadcn-htmx, htmx v4 + Tailwind v4.6//7// A server-backed action toggle (like / star / follow / pin). Clicking flips8// the appearance INSTANTLY to the toggled state, then reconciles with the9// server's HTML response — rolling back automatically if the request fails.10//11// Built on:12// - Real htmx v4 events, NOT an extension. htmx v4 does not ship a working13// "optimistic" attribute (the bundled src/ext/hx-optimistic.js is an14// unfinished stub — "TODO: this needs to be updated to use the new internal15// API" — and it does not flip aria-pressed nor cancel the error swap). So16// the behaviour is a tiny self-contained script (OPTIMISTIC_TOGGLE_JS,17// emitted once below) keyed on data-slot="optimistic-toggle":18// • htmx:before:request — save the button's innerHTML + aria-pressed,19// then flip aria-pressed and paint the <template>'s optimistic markup20// in (the instant pre-network flip).21// • htmx:before:swap — if the response is 4xx/5xx (ctx.response.status),22// preventDefault() to CANCEL the swap (htmx v4 swaps error bodies by23// default — see repos/htmx/src/htmx.js:1224) and restore the saved24// markup + aria-pressed (rollback).25// • on success htmx's hx-swap="outerHTML" replaces the button with the26// server's authoritative version — no rollback code needed.27// htmx v4 fires htmx:response:error for 4xx/5xx and lets a28// htmx:before:swap listener veto the swap via preventDefault:29// repos/htmx/CHANGELOG.md (htmx:response:error) and htmx.js:1224.30// - A native <template> holds the optimistic markup. <template> content is31// inert/not rendered until cloned, so it never shows until the script pulls32// its innerHTML. repos/mdn/files/en-us/web/html/reference/elements/template/index.md33// - A real <button> with aria-pressed: the platform gives us role=button and34// Space/Enter activation for free, and aria-pressed carries the toggle35// state. APG: Button (toggle) pattern — the accessible NAME must stay36// constant across states; only aria-pressed flips.37// repos/aria-practices/content/patterns/button/examples/button.html38// repos/mdn/files/en-us/web/accessibility/aria/reference/attributes/aria-pressed/index.md39//40// … truncated
More from shadcn-htmx
All 83 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | shadcn-htmx | Components | Free | no deps | |
| Active Searchactive-search | shadcn-htmx | Components | Free | no deps | |
| Alertalert | shadcn-htmx | Components | Free | no deps | |
| Alert Dialogalert-dialog | shadcn-htmx | Components | Free | no deps | |
| Aspect Ratioaspect-ratio | shadcn-htmx | Components | Free | no deps | |
| Auto Gridauto-grid | shadcn-htmx | Components | Free | no deps | |
| Autocompleteautocomplete | shadcn-htmx | Components | Free | no deps | |
| Autosize Textareaautosize-textarea | shadcn-htmx | Components | Free | no deps |
