shadcn-htmx — shadcn for htmx v4 + Tailwind v4

7 min read Original article ↗

htmx v4 — early preview

shadcn-style components, for the server.

A web-standards component library for htmx v4 + Tailwind v4. One source of truth — five flavours: Hono JSX, Jinja2, Go templates, Phoenix, and raw HTML. Copy what you need, ship in any stack.

Web standards first

Real <button>, real aria-pressed, real focus management. No reinventing what the platform already ships.

Five flavours, one design

Hono JSX, Jinja2, Go templates, Phoenix function components, and a raw HTML snippet — all generated from the same source of truth.

Copy, CLI, or curl

Install via npx shadcn add, curl the source file straight into your templates folder, or copy-paste the snippet. Your code, your style.

Tailwind v4 native

CSS-first config with @theme, @utility, and the Oxide engine. No legacy tailwind.config.js.

APG-compliant

Each component follows the WAI-ARIA Authoring Practices contract — keyboard interaction, focus management, ARIA roles, all checked against the spec source.

htmx v4 attribute set

All components type the v4 attribute set — hx-disable, the renamed swap modifiers, the new request lifecycle hooks.

Sponsors

Backed by people who build with this.

shadcn-htmx is open source and free to use. Sponsorship pays for maintenance time, new components, and keeping the docs current with htmx and Tailwind upstream releases.

Sponsors updated 2026-06-03.

Components

Eighty-two components. Every one, every flavour.

Each ships with the same install, live examples, and source view across all five frameworks — Hono JSX, Jinja2, Go templates, Phoenix, and raw HTML.

Forms

Autocomplete

Native typeahead — datalist suggestions, htmx-streamed.

Output

Live result region for a calculation or server action — native <output> with an implicit aria-live so htmx swaps announce themselves.

Segmented Control

{ label: "Segmented Control", href: "/docs/segmented-control", blurb: "Joined radio bar — pick a value, not a panel." },

Rating

{ label: "Rating", href: "/docs/rating", blurb: "Star rating as a native radio group — per-star labels, CSS hover preview, submits a real value. Zero JS." },

Color Picker

Color Picker — native <input type="color"> styled as a shadcn swatch with an optional live hex readout. The browser owns the whole picker UI and validates the CSS color.

Autosize Textarea

Autosize Textarea — a <textarea> that grows and shrinks to fit its content between min/max bounds using one CSS line (field-sizing: content) instead of the classic scrollHeight JS loop. Zero JavaScript; degrades to a plain fixed field where unsupported.

Cascading Select

Cascading Select — a pair of dependent native selects where picking the parent reloads the child's options (and an optional detail card) from the server in one request, using htmx's default change trigger plus an hx-swap-oob fragment. No JavaScript.

Form Field

Field-row wrapper composing label, control, description, and error — auto-wiring aria-describedby and a native :user-invalid styling hook. Plus a fieldset/legend group variant. Zero JS.

File Upload

Drag-and-drop or click to pick files — a native file input with previews and a multipart upload bar.

Date Time Picker

Native date, time, datetime-local, month and week fields with min/max/step constraints and normalized values — a web-standards date/time picker with no JS calendar library.

Active Search

Debounced live-search box that filters a results list as you type — inline spinner, stale-request cancellation, and a no-JS Enter fallback.

Edit In Place

Read-only record that swaps to a pre-filled form; Save PUTs, Cancel re-fetches.

Button

Six variants, four sizes, toggle + htmx hooks.

Input

Native types, ARIA-invalid, htmx live search.

Textarea

Auto-resize via field-sizing, htmx autosave.

Label

Click-to-focus, peer-disabled aware.

Checkbox

Indeterminate support, peer-checked indicator.

Combobox

Native datalist + htmx-filtered listbox.

Switch

role=switch pill, save-on-toggle pattern.

Radio Group

Arrow-key cycle straight from the platform.

Select

Native dropdown, cascading htmx demo.

Slider

Native range, full keyboard contract.

Number Input

Native number spinbutton with −/+ steppers

Range Slider

Two-thumb range from native range inputs

Listbox

Scrollable single/multi-select list (APG listbox)

Layout

Exclusive Accordion

Native details/summary, exclusive via shared name — zero JS.

Scroll Area

Constrained-overflow region with a themed native scrollbar and CSS-only fade masks that hint at more content — zero JavaScript.

Snap List

The bare scroll-snapping rail — gallery strip, chip row, media shelf, date rail. Pure CSS scroll-snap, zero JavaScript.

Container Card

Container Card — a card that adapts to its own width, not the viewport. The same markup stacks in a sidebar and goes side-by-side in a wide column, using CSS container queries. No JavaScript.

Sticky Header

Header that pins on scroll and reacts the instant it sticks — shadow + solid background via @container scroll-state(stuck), no sentinel, zero JS.

Aspect Ratio

Lock images, videos, and embeds to a fixed ratio that resizes fluidly — native CSS aspect-ratio, no layout shift, no JavaScript.

Auto Grid

Responsive grid that wraps into as many equal columns as fit — no breakpoints.

Card

Header / Content / Footer slots.

Table

Semantic table, sortable via aria-sort.

Collapsible

Native single show/hide disclosure

Toolbar

Group controls in one arrow-navigable tab stop

Grid

Interactive data grid with 2-D arrow-key cell navigation

Treegrid

Expandable hierarchical grid (role=treegrid)

Splitter

Resizable two-pane split with a draggable divider

Landmarks

Accessible landmark page-shell, native elements

Display

Kbd

Kbd — an inline keyboard-key badge. Renders a native <kbd> for a single key or nests one per key for shortcuts like Ctrl + Shift + R, the way command menus, docs, and tooltips show keystrokes. Phrasing content with no implicit role, so it ships zero JavaScript.

Highlight

Highlight — wrap the words that matched a search query in a native <mark>. Server-rendered, theme-token styled, zero JS; rides along in the fragment htmx swaps into your results list.

Relative Time

{ label: "Relative Time", href: "/docs/relative-time", blurb: "Semantic <time> timestamp — server renders a machine-readable datetime plus a human label; a tiny script re-localises to the visitor's locale and degrades to the server value with no JS." }

Figure

Captioned, self-contained content — image, diagram, code, or quote — in a native <figure> whose <figcaption> is its accessible name. No JS.

Responsive Image

Responsive Image — art-directed, format-switching image on native <picture> + <source>. Light/dark, AVIF/WebP/JPEG, per-viewport crops, all selected by the browser. Zero JS.

Media Player

Style a native HTML5 video or audio player — multiple source formats, WebVTT caption tracks, poster, and aspect-ratio framing. The browser provides the full accessible playback UI (play, scrub, volume, captions, fullscreen, PiP). Zero JavaScript.

Selectable Table

Data table with row checkboxes, select-all, and a bulk-action bar revealed by CSS :has(:checked). Bulk actions hx-post the checked rows.

Delete Row

Confirm, DELETE, fade out — in place. One inherited declaration covers every row.

Copy Button

Click-to-copy button built on the Async Clipboard API with a progressive-enhancement fallback. Flips to a transient aria-live "Copied" state. The docs code-block is a consumer.

Avatar

Image with text/icon fallback on 404.

Badge

Six variants; renders span or anchor.

Separator

Decorative or semantic divider.

Carousel

Native scroll-snap slideshow with APG carousel roles

Feedback

Scroll Progress

Reading-position bar that fills as you scroll — pure animation-timeline: scroll(), zero JS.

Optimistic Toggle

Instant like/follow/pin toggle — flips optimistically, reconciles with the server, rolls back on error.

Status

{ label: "Status", href: "/docs/status", blurb: "Polite live region for non-urgent updates — role=status/log, htmx swap-in." }

Lazy Load

Defer slow content past first paint — the container fetches its own body after render and swaps it in, with reserved space so the page never jumps.

Alert

Five variants + live-region politeness.

Progress

role=progressbar, htmx polling demo.

Skeleton

role=status placeholder, outerHTML swap.

Toast

Server-driven via htmx beforeend swap.

Meter

Native <meter> gauge, low/high/optimum zones.

Feed

Infinite-scroll list of articles, APG feed pattern

Overlays

Navigation

Split Button

Primary action welded to a disclosure toggle — one click for the default, the chevron for the rest.

Sidebar

Responsive app-nav sidebar — a fixed rail on desktop, an off-canvas drawer behind a labelled hamburger on mobile. Real anchors, CSS grid + :target, opens and closes with zero JavaScript.

Load More

Self-replacing pagination — button or scroll sentinel, zero JS.

Skip Link

Skip Link — a visually-hidden-until-focused "Skip to main content" link, the first focusable element on the page, jumping keyboard focus to the main landmark. Native <a href="#main"> + CSS focus reveal, zero JS.

Theme Toggle

Theme Toggle — light / dark / system colour-scheme switcher. Honours prefers-color-scheme by default, persists an explicit override in a cookie for a no-flash server render, and ships as a native radiogroup with full keyboard support.

Accordion

Native details/summary, exclusive via name.

Pagination

nav landmark, aria-current on active page.

Tabs

role=tab, arrow / Home / End contract.

Breadcrumb

Path-to-page trail: native nav + ol of links

Link

Native anchor; underlined/muted/hover + external.

Menubar

App-style menubar of native popover menus

Tree

Hierarchical role=tree with APG keyboard nav