Form Field
shadcn-htmx/form-fieldFreeComponent
Field-row wrapper composing label + control slot + description + error, auto-wiring aria-describedby and aria-invalid, with a native :user-invalid styling hook. Includes a fieldset/legend group variant. Ships in five flavours; zero JS.
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/form-field.jsonSource
1/** @jsxImportSource hono/jsx */2import type { Child } from "hono/jsx"3import { cloneElement, isValidElement } from "hono/jsx"4import { cn, type ClassValue } from "@/registry/lib/cn"56// Form Field — shadcn-htmx, htmx v4 + Tailwind v4.7//8// A field-row wrapper that composes a <label>, a single control slot, an9// optional description, and an optional error message — auto-wiring the10// label's `for`, the control's `aria-describedby` (description + error ids),11// and `aria-invalid`. The visual error state is driven by the native12// `:user-invalid` pseudo-class so the field only "turns red" AFTER the user13// has interacted and a submit was attempted — no JS, no premature errors.14//15// Source of truth (shadcn anatomy — FormField / FormItem / FormLabel /16// FormControl / FormDescription / FormMessage):17// repos/shadcn-ui/apps/v4/registry/new-york-v4/ui/form.tsx18// Upstream couples those parts to react-hook-form via React context. We have19// no client form runtime, so instead we lift the wiring to the server: one20// component reads `id`/`invalid`/`description`/`error`, derives the ids, and21// clones them onto the control child. Same semantic HTML, zero client state.22//23// Built on web platform primitives:24// - <fieldset>/<legend> for grouping multiple controls under one caption.25// repos/mdn/files/en-us/web/html/reference/elements/fieldset/index.md26// repos/mdn/files/en-us/web/html/reference/elements/legend/index.md27// - Constraint Validation + :user-invalid for "show error only after the28// user tried" styling. :invalid fires before interaction (confusing);29// :user-invalid fires only after a submit attempt + interaction.30// repos/mdn/files/en-us/web/css/reference/selectors/_colon_user-invalid/index.md31// repos/web.dev/src/site/content/en/learn/forms/validation/index.md (#javascript, :user-invalid aside)32// - aria-describedby to connect the control to its description + error.33// repos/mdn/files/en-us/web/accessibility/aria/reference/attributes/aria-describedby/index.md34// repos/web.dev/src/site/content/en/learn/forms/accessibility/index.md ("Help users find the error message")35//36// htmx: the field forwards hx-* untouched, so a server can swap the whole37// field via hx-swap="outerHTML" and flip aria-invalid + inject the error in38// one shot. See repos/htmx/www/reference.md.3940// Root row. `grid gap-2` mirrors shadcn FormItem. The `[&:has(:user-invalid)]`41// … 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 |
