Field
Wraps a control with its label, helper text and error message, and links them for assistive technology. Required and optional markers, vertical and horizontal layouts, groups.
Version 0.4.1 ·
Installation
bunx --bun shadcn@latest add @dga/fieldField is the base of every form control. Each control you add from this section installs it with it.
Usage
import { Field, FieldDescription, FieldError, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
export function NationalIdField({ error }: { error?: string }) {
return (
<Field name="nationalId" invalid={Boolean(error)}>
<FieldLabel required>National ID number</FieldLabel>
<Input required inputMode="numeric" />
<FieldDescription>10 digits, starting with 1 or 2.</FieldDescription>
<FieldError match={Boolean(error)}>{error}</FieldError>
</Field>
);
}Put one control in each Field. The label names the control, and the helper text and the error message are read after it through aria-describedby. Use Input, Textarea, Select, Number Input, Search Box, Checkbox, Radio, Switch or File Upload as the control.
Anatomy
- Field (
<div>): holds the state (invalid,disabled) that every part reads. - FieldLabel (
<label>): the visible name.requiredadds a red*,optionaladds the text "(Optional)". - Control: any form component from this section.
- FieldDescription (
<p>): helper text under the control. - FieldError: the message with an alert icon.
- FieldContent, FieldGroup, FieldSet, FieldLegend and FieldItem lay out groups and horizontal controls.
Examples
Required and optional
Mark required fields with required on the label and on the control, so the marker is seen and the requirement is announced. In a form where most fields are required, mark the exceptions with optional and translate the text with optionalLabel.
<FieldLabel required>Full name</FieldLabel>
<FieldLabel optional optionalLabel="Optional">Job title</FieldLabel>Error messages
Set invalid on the Field and match on FieldError to drive the error from your own state. Without match, the message shows when the browser's validation fails. The message always has an icon: the error never relies on colour alone.
A form
A building permit request built only from Field-based controls. Submit it empty to see every error.
Groups and horizontal controls
Use orientation="horizontal" with FieldContent for a checkbox or switch, and FieldSet with FieldLegend for a radio group or a set of checkboxes. FieldItem gives each radio its own label and helper text.
<Field orientation="horizontal">
<Checkbox />
<FieldContent>
<FieldLabel>I agree to the terms</FieldLabel>
<FieldDescription>You can withdraw consent later.</FieldDescription>
</FieldContent>
</Field>RTL
The label, helper text and error sit on the start side and the error icon comes first in reading order. The required marker follows the label text. Horizontal fields put the control on the start side.
Accessibility
| Key | Action |
|---|---|
| Tab | Moves focus to the control. |
| Click on the label | Focuses the control, or toggles a checkbox, radio or switch. |
- The label is linked to the control by Base UI, so it is its accessible name.
- FieldDescription and FieldError are added to the control's
aria-describedby, so they are read after the label. - An invalid control has
aria-invalid="true". The message has an icon and text, never colour alone (WCAG 1.4.1). - The
*marker is hidden from screen readers; setrequiredon the control so "required" is announced. - Groups use
<fieldset>and<legend>, so the group name is read with each control.
API Reference
Field
Wraps one form control with its label, helper text and error message. Links them for assistive technology: the label names the control and the helper text and error are announced through `aria-describedby`.
| Prop | Type | Default |
|---|---|---|
"vertical" | "horizontal"`vertical` stacks label, control, helper text and error. `horizontal` puts the control (checkbox, radio, switch) beside its label and text. | "vertical" | |
| ||
stringIdentifies the field when a form is submitted. Takes precedence over the `name` prop on the `<Field.Control>` component. | No default | |
| ||
booleanWhether the field is invalid. Useful when the field state is controlled by an external library. | No default | |
| ||
booleanWhether the component should ignore user interaction. Takes precedence over the `disabled` prop on the `<Field.Control>` component. | No default | |
| ||
Also accepts every prop of the Base UI Field (opens in a new tab).
FieldContent
Groups the label, helper text and error beside a horizontal control.
Also accepts every prop of the Base UI Field (opens in a new tab).
FieldDescription
Helper text under the control. Linked to the control with `aria-describedby`.
Also accepts every prop of the Base UI Field (opens in a new tab).
FieldError
The error message, with an icon so the error never relies on colour alone. It renders when the control fails validation, or whenever `match` is `true`. Set `invalid` on the Field and `match` here to control it from your own state.
| Prop | Type | Default |
|---|---|---|
boolean | "valueMissing" | "typeMismatch" | …Determines whether to show the error message according to the field's [ValidityState](https://developer.mozilla.org/en-US/docs/Web/API/ValidityState). Specifying `true` will always show the error message, and lets external libraries control the visibility. | No default | |
| ||
Also accepts every prop of the Base UI Field (opens in a new tab).
FieldGroup
Stacks several fields with the DGA spacing between them.
Also accepts every prop of the Base UI Field (opens in a new tab).
FieldItem
One checkbox or radio inside a group, so each has its own label and helper text.
Also accepts every prop of the Base UI Field (opens in a new tab).
FieldLabel
The visible name of the control. Clicking it focuses or toggles the control.
| Prop | Type | Default |
|---|---|---|
booleanShows the required marker (*). Also set `required` on the control so it is announced. | No default | |
| ||
booleanShows the optional marker, for fields that are not required in a form that mostly is. | No default | |
| ||
stringText of the optional marker. Translate it on Arabic pages. | "Optional" | |
| ||
Also accepts every prop of the Base UI Field (opens in a new tab).
FieldLegend
The name of a group of controls. Use it instead of a label on a Fieldset.
| Prop | Type | Default |
|---|---|---|
booleanShows the required marker (*). Also set `required` on the control so it is announced. | No default | |
| ||
booleanShows the optional marker, for fields that are not required in a form that mostly is. | No default | |
| ||
stringText of the optional marker. Translate it on Arabic pages. | "Optional" | |
| ||
Also accepts every prop of the Base UI Field (opens in a new tab).
FieldSet
Groups related controls (a radio group, a set of checkboxes) under a legend.
Also accepts every prop of the Base UI Field (opens in a new tab).
Deviations from DGA
- Field is not in the Figma file: it is derived from the label, helper and error parts of the input pages.
- The error is never colour alone:
aria-invalid, a red border, and a message that starts with an icon.
| Change | Reason |
|---|---|
Field | The same three parts appear on every control page. One component keeps them consistent and wires the accessibility attributes once. |
Field: error is never colour alone | WCAG 1.4.1: colour must not be the only cue. A border colour change alone fails it. |
Contrast
42 pairs checked · all pass WCAG 2.1 AAShow 7 statesHide
| Variant / state | Light | Dark |
|---|---|---|
| label | 17.31:1 AAA | 15.87:1 AAA |
| label (horizontal) | 13.91:1 AAA | 15.87:1 AAA |
| helper text | 4.57:1 AA | 6.32:1 AA |
| optional marker | 4.57:1 AA | 6.32:1 AA |
| required marker | 4.62:1 AA | 4.65:1 AA |
| error text | 6.29:1 AA | 9.01:1 AAA |
| error icon | 6.29:1 3:1 | 9.01:1 3:1 |
Text needs 4.5:1, icons and focus rings 3:1. Disabled states are exempt. Full contrast report