Capítulo 18 de 43

Chapter 18: Form

Core Idea

A form primitive built directly on the native browser Constraint Validation API, wiring label/control/error-message association and accessible announcement automatically, with support for both client-side and server-side validation.

Key Concepts

  • Anatomy: RootField (name-scoped) → Label + Control + Message + ValidityState, plus top-level Message/Submit.
  • Message's match prop: matches against the native ValidityState keys (e.g. "valueMissing", "typeMismatch") or a custom sync/async function (value, formData) => boolean.
  • data-invalid/data-valid: automatically applied to Field/Label/Control for validity-based styling, no manual state tracking.
  • Server-side validation: Field's serverInvalid prop plus Message's forceMatch let you reuse client-defined messages for server errors; Root's onClearServerErrors clears them on resubmit/reset.
  • ValidityState render prop: exposes the raw native validity object when you need custom logic beyond what Message covers (e.g. driving a third-party input component's visual state).

Code Examples

<Form.Field name="email" serverInvalid={serverErrors.email}>
  <Form.Label>Email address</Form.Label>
  <Form.Control type="email" required />
  <Form.Message match="valueMissing">Please enter your email.</Form.Message>
  <Form.Message match="typeMismatch" forceMatch={serverErrors.email}>
    Please provide a valid email.
  </Form.Message>
</Form.Field>
  • What it demonstrates: one client-side validation message (valueMissing) plus one message reused for both client (typeMismatch) and server (forceMatch={serverErrors.email}) validation on the same field.

Reference Tables

PartKey props
Fieldname*, serverInvalid
Messagematch (ValidityState key or function), forceMatch, name (required if used outside Field)
RootonClearServerErrors

Anti-patterns

  • Composing Form.Control directly with other Radix form primitives (Checkbox, Select): not supported as of this doc — those need separate wiring, not asChild composition with Form.Control.

Key Takeaways

  1. Default (childless) Form.Message match="valueMissing" renders a sensible built-in message — pass children only when you need custom copy or i18n.
  2. Reuse the same Message/match pair for both client and server validation via forceMatch instead of maintaining two separate error-rendering paths.
  3. Focus automatically moves to the first invalid control on failed validation — no manual focus management needed.

Connects To

  • Checkbox / Radio Group / Select: not yet directly composable inside Form.Control — treat as a known limitation, not a bug in your integration.