Field
Fields represent an individual section of a form containing an associated control and label, as well as any description or validation messages.
Your name will be visible on your profile.
Installation
Base UI components are all available as a single package.
npm install @base-ui-components/react
Once you have the package installed, import the component.
import { Field } from '@base-ui-components/react/Field';
Anatomy
Fields are implemented using a collection of related components:
<Field.Root />
is a top-level component that wraps all other components.<Field.Control />
renders a control when not using a native Base UI input component.<Field.Label />
renders a label for the control.<Field.Description />
renders an optional description for the control to provide additional information.<Field.Error />
renders error messages for the control.<Field.Validity />
accepts a function as a child that enables reading rawValidityState
to render custom JSX.
<Field.Root>
<Field.Control />
<Field.Label />
<Field.Description />
<Field.Error />
<Field.Validity />
</Field.Root>
Labeling and descriptive help text
All Base UI input components are aware of Base UI's Field
component. The label and description are automatically wired to these components when placed inside a Field.Root
:
<Field.Root>
<Checkbox.Root>
<Checkbox.Indicator />
</Checkbox.Root>
<Field.Label>My checkbox</Field.Label>
<Field.Description>My description</Field.Description>
</Field.Root>
When using a custom component which is not aware of Base UI's Field
, use Field.Control
:
<Field.Root>
<Field.Control />
<Field.Label>My input</Field.Label>
<Field.Description>My description</Field.Description>
</Field.Root>
The render
prop allows you to pass a custom component or tag, different from the default of input
:
<Field.Control render={<select />} />
Validation
When adding native HTML validation props like required
or pattern
, Field.Error
renders error messages inside of it automatically:
<Field.Root>
<Field.Label>My input</Field.Label>
<Field.Control required />
<Field.Error />
</Field.Root>
The children
by default is the browser's native message, which is automatically internationalized. You may pass custom children
instead:
<Field.Root>
<Field.Control required />
<Field.Error>Field is required</Field.Error>
</Field.Root>
Individual constraint validation failures
When there are multiple HTML validation props, you can target individual validity state failures using the match
prop to render custom messages:
<Field.Root>
<Field.Control required pattern="[a-zA-Z0-9]+" />
<Field.Error match="valueMissing">Field is required</Field.Error>
<Field.Error match="patternMismatch">Only alphanumeric characters allowed</Field.Error>
</Field.Root>
For the list of supported match
strings, visit ValidityState
on MDN.
Custom validation
In addition to the native HTML constraint validation, custom validation can be used by specifying a validate
function on Field.Root
. It receives the control's value
as its argument, and returns an error string or array of error strings if the field is invalid, or null
otherwise.
<Field.Root
validate={(value) =>
value === 'password' ? 'Cannot literally use `password` as your password.' : null
}
>
<Field.Control type="password" />
<Field.Label>Password</Field.Label>
<Field.Error />
</Field.Root>
For Base UI input components, value
represents the component's value type, while for native
elements, it is always the native element.value
DOM property. Attach a ref
to the Control
element and access it to read its state inside the validate
function for further control as an
alternative if necessary.
To customize the rendering of multiple messages, you can use the Validity
subcomponent:
<Field.Root
validate={(value) => {
const errors = [];
if (value.length < 8) {
errors.push('Password must be at least 8 characters long.');
}
if (value === 'password') {
errors.push('Cannot literally use `password` as your password.');
}
return errors;
}}
>
<Field.Control type="password" />
<Field.Label>Password</Field.Label>
<Field.Error>
<ul>
<Field.Validity>
{(state) => state.errors.map((error) => <li key={error}>{error}</li>)}
</Field.Validity>
</ul>
</Field.Error>
</Field.Root>
The Validity
subcomponent enables rendering custom JSX based on the state
parameter, which contains the following properties:
state.validity
, the field'sValidityState
state.errors
, an array of custom errors returned from thevalidate
prop (if present)state.error
, a custom error string returned from thevalidate
prop (if present)state.value
, the field control's current valuestate.initialValue
, the field control's initial value upon mount
It can be placed anywhere inside Field.Root
, including other Field subcomponents.
Controlled validity
When the invalid
prop is applied to Field.Root
, the Field is placed into an invalid state regardless of client-side validation. In this state, a given Field.Error
message can be forced to be shown by specifying a forceShow
prop.
This is useful for server-side error messages, or displaying errors initially during SSR phase.
const [serverErrors, setServerErrors] = React.useState({
email: false,
});
return (
<Field.Root invalid={serverErrors.email}>
<Field.Control type="email" required />
<Field.Error match="valueMissing">Client-side only error message</Field.Error>
<Field.Error match="typeMismatch" forceShow={serverErrors.email}>
Client + server-side error message
</Field.Error>
<Field.Error forceShow={serverErrors.email}>Server-side only message</Field.Error>
</Field.Root>
);
The show
prop is for client-side validation, while the forceShow
prop is for server-side validation. Both can be combined together to share the same error message.
Performing an email validity check on the server:
Errors shown initially for password validation:
- Password must be at least 8 characters long.
- Password must contain at least 2 uppercase letters.
- Password must contain at least 2 unique symbols from the set [!@#$%^&*].
Realtime and async validation
validationMode="onChange"
reports the validity of the control on every change
event instead of blur
:
<Field.Root validationMode="onChange">
The validate
function can also be async by returning a promise, enabling inline server-side validation through network requests.
In the demo below, the taken names are admin
, root
, and superuser
— every other name is available. For demonstration purposes, a fake network request that takes 500ms is initiated to mimic a trip to the server to check for availability on the back-end.
Handle availability checker
Enter a name
The onChange
validation is debounced by 500ms to avoid firing a network request on every keystroke by specifying the validationDebounceTime
prop:
<Field.Root validationMode="onChange" validationDebounceTime={500}>
Styling
The [data-valid]
and [data-invalid]
style hooks determine if the field is valid or not:
<Field.Root>
<Field.Control required className="FieldControl" />
</Field.Root>
.FieldControl[data-invalid] {
color: red;
}
[data-touched]
is applied if the field has been "touched": blurred after being interacted with, or submitted if pressing Enter on an input.
.FieldControl[data-touched] {
color: red;
}
[data-dirty]
is applied if the field's value has been changed from its initial one.
.FieldControl[data-dirty] {
color: orange;
}
API Reference
FieldRoot
The foundation for building custom-styled fields.
Prop | Type | Default | Description |
---|---|---|---|
className | union | Class names applied to the element or a function that returns them based on the component's state. | |
disabled | bool | false | Whether the field is disabled. Takes precedence over the disabled prop of the Field.Control component. |
invalid | bool | Determines if the field is forcefully marked as invalid. | |
name | string | The field's name. Takes precedence over the name prop of the Field.Control component. | |
render | union | A function to customize rendering of the component. | |
validate | func | Function to custom-validate the field's value. Return a string or array of strings with error messages if the value is invalid, or null if the value is valid. The function can also return a promise that resolves to a string, array of strings, or null . | |
validationDebounceTime | number | 0 | The debounce time in milliseconds for the validate function in onChange phase. |
validationMode | enum | 'onBlur' | Determines when validation should be triggered. |
FieldLabel
A label for the field's control.
Prop | Type | Default | Description |
---|---|---|---|
className | union | Class names applied to the element or a function that returns them based on the component's state. | |
render | union | A function to customize rendering of the component. |
FieldDescription
A description message for the field's control.
Prop | Type | Default | Description |
---|---|---|---|
className | union | Class names applied to the element or a function that returns them based on the component's state. | |
render | union | A function to customize rendering of the component. |
FieldError
Displays error messages for the field's control.
Prop | Type | Default | Description |
---|---|---|---|
className | union | Class names applied to the element or a function that returns them based on the component's state. | |
forceShow | bool | Determines whether the error message should be shown regardless of the field's client validity. | |
match | enum | Determines whether the error message should be shown when it matches a given property of the field's ValidityState . | |
render | union | A function to customize rendering of the component. |
FieldControl
The field's control element. This is not necessary to use when using a native Base UI input component (Checkbox, Switch, NumberField, Slider, Radio Group etc).
Prop | Type | Default | Description |
---|---|---|---|
className | union | Class names applied to the element or a function that returns them based on the component's state. | |
onValueChange | func | Callback fired when the value changes. Use when controlled. | |
render | union | A function to customize rendering of the component. |
FieldValidity
Render prop component that provides the field's validity state and value to its children.
Prop | Type | Default | Description |
---|