Skip to main content

Overview

Form provides a wrapper around form controls with built-in validation, error messaging, and accessibility features. It handles form state, validation messages, and proper ARIA attributes automatically.

Features

  • Built-in client-side and server-side validation
  • Automatic error message display
  • Accessible by default with proper ARIA attributes
  • Customizable validity state handling
  • Works with native HTML form elements
  • Supports custom validation messages
  • Integration with browser’s constraint validation API

Installation

npm install @radix-ui/react-form

Anatomy

import * as Form from '@radix-ui/react-form';

export default () => (
  <Form.Root>
    <Form.Field>
      <Form.Label />
      <Form.Control />
      <Form.Message />
    </Form.Field>
    <Form.Submit />
  </Form.Root>
);

API Reference

Root

Contains all the form component parts. Renders a <form> element.
onSubmit
(event: React.FormEvent<HTMLFormElement>) => void
Event handler called when the form is submitted.
onClearServerErrors
() => void
A function to clear server errors. This is called when the user interacts with a field.
asChild
boolean
default:"false"
Change the default rendered element for the one passed as a child.

Field

Groups a label, control, and message together. Automatically manages IDs and ARIA attributes.
name
string
required
The name of the field. This is used to match the field with validation messages.
serverInvalid
boolean
When true, indicates the field has a server error.
asChild
boolean
default:"false"
Change the default rendered element for the one passed as a child.

Label

The label associated with a form control.
asChild
boolean
default:"false"
Change the default rendered element for the one passed as a child.

Control

The form control (input, textarea, select, etc.). This should be used with native form elements or custom form controls.
asChild
boolean
default:"false"
Change the default rendered element for the one passed as a child.

Message

Displays validation messages for a field.
match
'valueMissing' | 'typeMismatch' | 'patternMismatch' | 'tooLong' | 'tooShort' | 'rangeUnderflow' | 'rangeOverflow' | 'stepMismatch' | 'badInput' | 'valid' | ((validity: ValidityState, formData: FormData) => boolean)
Used to target a specific validity state or provide a custom matcher function. When the matcher succeeds, the message will be shown.
forceMatch
boolean
When true, always shows the message regardless of validity state.
asChild
boolean
default:"false"
Change the default rendered element for the one passed as a child.

ValidityState

Provides access to the field’s validity state. Useful for custom UI based on validation state.
children
(validity: ValidityState) => React.ReactNode
required
A render prop that receives the validity state.

Submit

The submit button for the form.
asChild
boolean
default:"false"
Change the default rendered element for the one passed as a child.

Example

import * as Form from '@radix-ui/react-form';
import './styles.css';

export default () => (
  <Form.Root className="FormRoot">
    <Form.Field className="FormField" name="email">
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
        <Form.Label className="FormLabel">Email</Form.Label>
        <Form.Message className="FormMessage" match="valueMissing">
          Please enter your email
        </Form.Message>
        <Form.Message className="FormMessage" match="typeMismatch">
          Please provide a valid email
        </Form.Message>
      </div>
      <Form.Control asChild>
        <input className="Input" type="email" required />
      </Form.Control>
    </Form.Field>

    <Form.Field className="FormField" name="question">
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
        <Form.Label className="FormLabel">Question</Form.Label>
        <Form.Message className="FormMessage" match="valueMissing">
          Please enter a question
        </Form.Message>
      </div>
      <Form.Control asChild>
        <textarea className="Textarea" required />
      </Form.Control>
    </Form.Field>

    <Form.Submit asChild>
      <button className="Button" style={{ marginTop: 10 }}>
        Submit
      </button>
    </Form.Submit>
  </Form.Root>
);

Accessibility

Automatically manages ARIA attributes including aria-invalid, aria-describedby, and proper label associations.

Features

  • Automatic ID generation for labels and controls
  • Error messages are properly associated with controls
  • Invalid states are announced to screen readers
  • Works with browser’s built-in form validation
  • Submit button is properly disabled during submission

Build docs developers (and LLMs) love