Patterns

Form

Accessible form wrappers: field ids, described-by wiring, error summary, and action rhythm without locking the system to one form library.

installnpx shadcn@latest add https://ds.bartoszrychlicki.com/r/br-form.json

Preview

Use a company email.
Two or three sentences are enough.
import { FormShell, FormField, FormErrorSummary, FormActions } from "@/components/br/form";
import { Button, Input } from "@/components/br/primitives";

<FormShell>
  <FormErrorSummary errors={[
    { id: "email", label: "Email", message: "Use a company email." },
  ]} />
  <FormField id="email" label="Email" error="Use a company email.">
    {(field) => <Input {...field} placeholder="you@studio.co" />}
  </FormField>
  <FormActions>
    <Button variant="ghost">Cancel</Button>
    <Button>Save</Button>
  </FormActions>
</FormShell>

Props

PropTypeDefaultDescription
children(fieldProps) => ReactNodeReceives id, aria-invalid, and aria-describedby.
errorReactNodeShown below the field and wired to the control.
hintReactNodeHelper text when there is no error.
errors{ id?, label, message }[]Summary rows linking to invalid fields.

Notes

RHF/Zod can own validation state; pass their errors into FormField and FormErrorSummary.