Forms & Validation
Build accessible forms with validation.
Forms are built from two pieces: Field, which groups a control with its label,
description, and error message and wires up the accessibility relationships; and
Form, which coordinates the fields and surfaces server-side errors. Both wrap
Base UI primitives.
Anatomy of a field
A Field composes a label, a control, an optional description, and an error
slot. The for/id and aria-describedby associations are handled for you.
Validation
Native constraints
Standard HTML attributes — required, type, min, maxLength, pattern —
are validated automatically. Point FieldError at a specific failure with
match, or render the browser's default message with a bare <FieldError />:
Custom validation
For rules HTML can't express, pass a validate function to the Field. Return a
string (or array of strings) to fail, or null to pass. Control when it runs
with validationMode ('onBlur' or 'onChange'):
validate can be async — return a promise — which is handy for availability
checks against an API.
Shake on invalid
For an extra cue when validation fails, hang the animate-shake utility off the
control's invalid state. Base UI sets data-invalid on the control when the field
fails validation, so put the class on the Input to shake just the control:
The shake plays once, when the field becomes invalid (the moment data-invalid is added) — not on every failed
submit while it stays invalid. Gating it behind motion-safe: keeps it off for users who prefer reduced motion, per
Animation.
Grouping with Fieldset
Use Fieldset and FieldsetLegend to group related fields under a shared label
(an accessible <fieldset>/<legend>):
The Form wrapper
Form ties the fields together and handles submission. Its most useful job is
displaying server-side errors: return them keyed by field name and pass
them to errors, and each Field shows its message in place.
Inputs are uncontrolled by default — read values from FormData on submit, as above. You can still control any field
with value/onValueChange (or onChange) when you need to.
Accessibility
Labels, descriptions, and error messages are associated with their control
automatically, and invalid fields are marked with aria-invalid. See
Accessibility — and note that grouped controls
(RadioGroup, CheckboxGroup) are labeled with aria-label/aria-labelledby,
not FieldLabel.