A React field with a Liquid Glass label, description, and validation message for one form control.
Field wraps one Base UI form control with a visible label, supporting text, and a validation message. It owns the labeling and validity wiring, while the child control owns its own glass surface and interaction.
Use Field to give Input a visible label, description, and validation message. Controls that already render their own label, such as Checkbox, Select, CheckboxGroup, RadioGroup, and Switch, keep their built-in label prop. Use Fieldset when several fields need one shared legend.
Pass the control as children. Field renders a real <label> and connects it to the control, so the input needs no separate label. children must be a single Base UI control; a native <input> is not wired into the field context.
validate receives the current value and returns a string, an array of strings, or nothing when the value is valid. validationMode controls when it runs: onSubmit by default, or onBlur and onChange for earlier feedback. validationDebounceTime delays onChange validation while typing.
Native constraints such as required, minLength, pattern, and type participate automatically because the control is a real form element.
Set error to show an externally controlled message. A string renders directly as the message. A truthy error marks the field invalid and takes precedence over built-in validation until it is cleared. The message is linked to the control with aria-describedby, and the control receives aria-invalid.
Pass a React element as error to take over the entire error body. The outer message element still owns the id and aria-describedby wiring, so custom content stays accessible.
Supports xs / sm / md / lg / xl, defaulting to md. Pass the same size to the control so the label, message, and control rows stay aligned.
Field renders a real <label> linked to the control. description and error register their ids with the control's aria-describedby; an error also sets aria-invalid on the control.
Keyboard behavior belongs to the wrapped control. Use label rather than a placeholder so the accessible name survives zoom, translation, and voice control. Group controls keep their own label; use Fieldset for a shared legend. When the field is disabled, the label and message fade and the control is disabled through the shared field state. See the accessibility guide for form patterns.
Field
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactElement | — | Single Base UI control labelled and validated by the field. Required. |
label | ReactNode | — | Visible label associated with the control. |
description | ReactNode | — | Supporting text rendered under the control and linked with aria-describedby. |
error | ReactNode | — | Error message. A string renders directly; a React element replaces the body. A truthy value marks the field invalid. |
size | "xs" | "sm" | "md" | "lg" | "xl" | "md" | Label, message, and spacing size. |
validate | (value, formValues) => string | string[] | null | void | Promise<...> | — | Custom validation. Return a message or messages when the value is invalid. |
validationMode | "onSubmit" | "onBlur" | "onChange" | "onSubmit" | When the field validates. |
validationDebounceTime | number | 0 | Delay in milliseconds between validate calls in onChange mode. |
invalid | boolean | — | Marks the field invalid from external state. |
disabled | boolean | false | Disables the control through the field and fades the label and message. |
name | string | — | Form field name registered by the field. |
dirty | boolean | — | Marks the field dirty from external state. |
touched | boolean | — | Marks the field touched from external state. |
actionsRef | RefObject<Field.Root.Actions | null> | — | Imperative actions. validate validates the field on demand. |
className | string | — | Tailwind classes merged into the field root. |
style | CSSProperties | — | Inline styles merged into the same element as className. |
ui | { root?: ClassValue; label?: ClassValue; error?: ClassValue; description?: ClassValue } | — | Tailwind classes for internal slots, keyed by data-slot. |
render | ReactElement | ((props, state) => ReactElement) | — | Replaces the field root element. |
Additional Base UI Field.Root props are forwarded, including id. The child control also accepts its own props; set required, disabled, and native constraints on the control when they belong to that element.
| Attribute | Description |
|---|---|
data-disabled | Present when the field is disabled. |
data-valid | Present when the field is valid. |
data-invalid | Present when the field is invalid. |
data-dirty | Present when the field value has changed. |
data-touched | Present after the field is touched. |
data-filled | Present when the control has a value. |
data-focused | Present when the control is focused. |
data-slot | Marks internal parts (root, label, error, description) for styling. |
Field has no glass surface of its own; it inherits the control's material. Tune the shared --ui-drop-shadow-label token for the label, adjust spacing and type with --ui-field-gap, --ui-field-label-size, and --ui-field-message-size, and use ui for internal slots keyed by data-slot. The error message uses text-red-700 in light themes and ui-dark:text-red-400 in dark themes; override it with ui.error. A custom error node renders directly inside ui.error. Component-specific values live in src/theme/field.ts. See the theming guide for token layers and presets.
Field.