Field
A Field pairs one control with the label, the description, and the error message that tell users what to enter.
When to Use
- for each control of a form: an Input, a Textarea, a Select, or a Slider
- as a horizontal Field, to place a Checkbox, a radio, or a Switch next to its label
- as a field set, to place several Fields under one legend, such as the lines of a billing address
- as a choice card, when each option of a Radio Group needs a title and a description
When Not to Use
- for a control whose name isn’t shown, such as the search box above a Table (set
aria-labelon the control) - for one control with a name and nothing else, such as the only Input of a Dialog (use a Label)
Anatomy
The parts in field.tsx build a Field, a field set, and a choice card.
Field
Invoices go to this address.
| Element | Usage |
|---|---|
| Label | Required |
| Control | Required |
| Description | Optional |
| Error | Invalid state only |
Field stacks its children and stretches them to its own width.
Field Set and Field Group
| Element | Usage |
|---|---|
| Legend | Required |
| Description | Optional |
| Field | Required |
| Field group | Optional |
FieldSet renders a fieldset, and FieldLegend names it. FieldGroup stacks Fields, and it’s the container that a responsive Field is measured against.
Choice Card
| Element | Usage |
|---|---|
| Title | Required |
| Control | Required |
| Description | Optional |
| Card | Required |
A choice card is a Field whose FieldLabel wraps a FieldContent and the control, so users can click anywhere on the card to change the control. Use FieldTitle for the title because the card itself is the label. The control can be a radio, a Checkbox, or a Switch.
States
A choice card shows the focus outline on its own edge, not on the control inside it.
Invalid
A Field is invalid when invalid is set, when its control fails validation, or when Base UI’s Form has an error for the control’s name. The control then has aria-invalid. Add a FieldError after the control, as color alone doesn’t tell users what is wrong.
FieldError that says what to enter.Disabled
If disabled is set on Field, the control is disabled, and the label can’t be clicked.
Required
Field has no required prop and adds no mark to the label. Set required on the control. A native input then reports the state to assistive technology, and the browser prevents the form from being submitted while the input is empty.
Behavior
orientation on Field sets whether the label is above the control or next to it.
| Orientation | Layout |
|---|---|
vertical | A column, in which the parts fill the Field’s width |
horizontal | A row, in the order of the markup: a Checkbox before its label, a Switch after it |
responsive | A column until the FieldGroup around it is 448px wide, then a row |
In a row, FieldContent contains the label and the description in one column and fills the width that remains next to the control.
Responsive
A responsive Field responds to the width of its FieldGroup, not of the screen, so the same form is stacked in a 384px Sheet and laid out in rows in a 576px Dialog. If there is no FieldGroup, the Field stays a column. See Layout for the rule.
Separator
FieldSeparator renders a Separator between two Fields of a FieldGroup. Its children are displayed as text centered on the line.
Content
| String | Rule | Example | Counterexample |
|---|---|---|---|
| Label | Name the value in sentence case, with no colon | “Billing email” | “Billing Email:” |
| Description | Say what the value is used for or what format it has | “Invoices and receipts go to this address.” | “Enter your billing email.” |
| Error | Say what to enter | “Enter a valid email address.” | “Invalid input.” |
| Legend | Name what the fields have in common | “Billing address” | “Details” |
Allow a label and an error to wrap. See Typography for the rule on truncation.
Accessibility
Field is Base UI’s Field with role="group". The FieldLabel names the control, and the FieldDescription and the FieldError are the control’s accessible description, which screen readers read together with the control. The error has role="alert", so screen readers announce the message when it appears. A Field can’t receive focus, and the control inside keeps its own keys.
A Field connects any registry control that holds a value. A Toggle Group and a Segmented Control are groups of buttons, and a Field connects nothing to them.
A Field takes one control. For several controls under one label, such as a first and a last name, use a FieldSet with a Field for each control. Two controls in one Field take the same label and the same form name.
A control with an error needs aria-invalid so that assistive technology can identify it, as WCAG 2.2 SC 3.3.1 Error Identification
requires. An invalid Field sets it. A FieldError with a message of your own doesn’t make the Field invalid: set
invalid with it.
Outside a Field, a FieldLabel, a FieldDescription, and a FieldError render plain elements and connect to no control.
Installation
npx shadcn@latest add @summit/fieldThe CLI also adds @summit/label and @summit/separator.
Usage
Field lays out, colors, and connects its parts. You provide invalid and the error text.
import { Field, FieldDescription, FieldLabel } from '@/components/ui/field';
import { Input } from '@/components/ui/input';
<Field>
<FieldLabel>Billing email</FieldLabel>
<Input type="email" />
<FieldDescription>Invoices and receipts go to this address.</FieldDescription>
</Field>;Show an Error
To show an error that your own code holds, set invalid on Field and place the message in a FieldError. A FieldError with no content shows nothing while the Field is valid, so the same markup covers both states.
<Field invalid={Boolean(error)}>
<FieldLabel>Billing email</FieldLabel>
<Input type="email" />
<FieldError>{error}</FieldError>
</Field>Word a Validation Message
A Field validates its control when users press Enter in it. A FieldError with no content then shows the browser’s message. To word the message yourself, set match on a FieldError. To add a rule, pass a function to validate on Field.
<FieldError match="valueMissing">Enter your billing email.</FieldError>
<FieldError match="typeMismatch">Enter a valid email address.</FieldError>Base UI also has a Form that holds the errors of a server by field name. See the Base UI Form documentation.
Show Several Errors
To show several errors, pass a list of objects with a message to errors. FieldError removes repeated messages, renders one message as text and several as a list, and renders nothing if the list is empty.
<FieldError errors={[{ message: 'Enter a valid email address.' }, { message: 'Use an address at your company.' }]} />Beside a Checkbox or a Switch
To place the label next to a Checkbox or a Switch, set orientation="horizontal", and wrap the label and the description in FieldContent.
import { Checkbox } from '@/components/ui/checkbox';
<Field orientation="horizontal">
<Checkbox defaultChecked />
<FieldContent>
<FieldLabel>Attach a PDF copy</FieldLabel>
<FieldDescription>Every invoice email carries the invoice as a PDF file.</FieldDescription>
</FieldContent>
</Field>;Name a Group of Options
To name a Radio Group, pass it to render on FieldSet, and set variant="label" on FieldLegend. The legend then names the Radio Group and has the size of a label. A Field in that FieldSet is one option, with its own label. A FieldDescription and a FieldError in the outer Field describe the whole group.
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
<Field invalid={Boolean(error)}>
<FieldSet render={<RadioGroup defaultValue="net-30" />}>
<FieldLegend variant="label">Payment terms</FieldLegend>
<Field orientation="horizontal">
<RadioGroupItem value="net-15" />
<FieldLabel>Net 15</FieldLabel>
</Field>
<Field orientation="horizontal">
<RadioGroupItem value="net-30" />
<FieldLabel>Net 30</FieldLabel>
</Field>
</FieldSet>
<FieldError>{error}</FieldError>
</Field>;For a group of Checkboxes, keep the FieldSet as a fieldset, and place the Fields in a FieldGroup with data-slot="checkbox-group".
Build a Choice Card
To build a choice card, wrap a FieldContent and the control in the FieldLabel of an option.
<Field>
<FieldLabel>
<FieldContent>
<FieldTitle>Hourly</FieldTitle>
<FieldDescription>Bill the time you track at an hourly rate.</FieldDescription>
</FieldContent>
<RadioGroupItem value="hourly" />
</FieldLabel>
</Field>API Reference
Field accepts the props of Base UI’s Field.Root, and FieldSet and FieldLegend accept the props of its Fieldset.Root and Fieldset.Legend. See the Base UI Field documentation for name, validate, and validationMode, and the Base UI Fieldset documentation. The other parts accept the props of their elements, and FieldLabel accepts the props of a Label.
Field
| Prop | Type | Default | Description |
|---|---|---|---|
orientation | 'vertical' | 'horizontal' | 'responsive' | 'vertical' | The direction of the label and the control |
invalid | boolean | false | Marks the control as invalid and colors the label |
disabled | boolean | false | Disables the control and dims the label |
FieldSet
| Prop | Type | Default | Description |
|---|---|---|---|
render | An element or a function that returns one | None | The element to render in place of the fieldset, such as a RadioGroup |
FieldLegend
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'legend' | 'label' | 'legend' | The text size of a legend or of a label |
FieldError
| Prop | Type | Default | Description |
|---|---|---|---|
errors | Array<{ message?: string } | undefined> | None | The messages to display when the part has no children |
match | boolean | keyof ValidityState | None | The validation failure that the message is for. true always shows the message, and is the default when the part has content |