Skip to content

Form

Validated form built on Base UI Form and Field.

This is your public display name.

Install

Bash
npx @madeui/cli add form

Usage

TSX
import { Form } from '@/components/ui/form';
import {
  Field,
  FieldDescription,
  FieldError,
  FieldLabel,
} from '@/components/ui/field';

Composition

TSX
<Form onFormSubmit={(values) => {}}>
  <Field name="email">
    <FieldLabel />
    <Input />
    <FieldDescription />
    <FieldError />
  </Field>
  <Button type="submit" />
</Form>

Form validates the Fields inside it. A field’s control is whatever Base UI control you place in it — Input, Textarea, Checkbox, Select, Switch, RadioGroup, Slider, NumberField all join the field automatically (label association, aria-describedby, aria-invalid). Native constraint attributes (required, type="email", minLength, …) and the field’s validate function both feed FieldError.

Server errors

Pass externally produced errors — e.g. from a server action — via errors, keyed by field name:

TSX
const [errors, setErrors] = React.useState({});

<Form
  errors={errors}
  onFormSubmit={async (values) => {
    const response = await submit(values);
    if (response.errors) setErrors(response.errors); // { email: 'Already in use' }
  }}
>

React Hook Form

Base UI fields interoperate with react-hook-form: keep RHF as the source of truth, tell the field about it with invalid, and render RHF’s message through FieldError (external errors render as-is). Use a plain <form> — RHF owns submission.

  • invalid puts the field into its invalid state (aria-invalid, red label) under RHF’s control.
  • FieldError errors={[...]} renders RHF’s messages directly — de-duplicated, nothing when empty.
  • register spreads name, ref, onChange, onBlur onto our Input, which forwards them to the native element.

For controlled Base UI controls (Select, Checkbox, Slider, …) use RHF’s Controller and map field.value / field.onChange to the control’s value / onValueChange (or checked / onCheckedChange).

TanStack Form

The same pattern works with TanStack Form — its form.Field render prop supplies state and handlers, our Field renders it accessibly:

API reference

Built on Base UI Form. All props are forwarded (errors, onFormSubmit, validationMode, actionsRef, …); see the Base UI Form API reference. See Field for the field parts.

PropTypeDefaultDescription
validationMode'onSubmit' | 'onBlur' | 'onChange''onSubmit'When fields validate; a field’s own validationMode wins.
errorsRecord<string, string | string[]>—External errors keyed by field name (e.g. from a server).
onFormSubmit(values) => void—Called with the form values when validation passes.
styleStyleXStyles—StyleX styles merged last — always win over the component’s own styles.

Was this page helpful?