Skip to content

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 ·

Label, helper text and error

Installation

bunx --bun shadcn@latest add @dga/field

Field is the base of every form control. Each control you add from this section installs it with it.

Usage

page.tsx
tsx
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. required adds a red *, optional adds 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.

page.tsx
tsx
<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.

A form

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.

page.tsx
tsx
<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.

LTR (English)
RTL (Arabic)

Accessibility

KeyAction
TabMoves focus to the control.
Click on the labelFocuses 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; set required on 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`.

Field props
PropTypeDefault
"vertical" | "horizontal"

`vertical` stacks label, control, helper text and error. `horizontal` puts the control (checkbox, radio, switch) beside its label and text.

"vertical"
string

Identifies the field when a form is submitted. Takes precedence over the `name` prop on the `<Field.Control>` component.

No default
boolean

Whether the field is invalid. Useful when the field state is controlled by an external library.

No default
boolean

Whether 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.

FieldError props
PropTypeDefault
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.

FieldLabel props
PropTypeDefault
boolean

Shows the required marker (*). Also set `required` on the control so it is announced.

No default
boolean

Shows the optional marker, for fields that are not required in a form that mostly is.

No default
string

Text 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.

FieldLegend props
PropTypeDefault
boolean

Shows the required marker (*). Also set `required` on the control so it is announced.

No default
boolean

Shows the optional marker, for fields that are not required in a form that mostly is.

No default
string

Text 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.
ChangeReason
FieldThe same three parts appear on every control page. One component keeps them consistent and wires the accessibility attributes once.
Field: error is never colour aloneWCAG 1.4.1: colour must not be the only cue. A border colour change alone fails it.

View all 2 deviations for this component

Contrast

42 pairs checked · all pass WCAG 2.1 AAShow 7 states
Variant / stateLightDark
label17.31:1 AAA15.87:1 AAA
label (horizontal)13.91:1 AAA15.87:1 AAA
helper text4.57:1 AA6.32:1 AA
optional marker4.57:1 AA6.32:1 AA
required marker4.62:1 AA4.65:1 AA
error text6.29:1 AA9.01:1 AAA
error icon6.29:1 3:19.01:1 3:1

Text needs 4.5:1, icons and focus rings 3:1. Disabled states are exempt. Full contrast report