Field
Gives an input its label and error.
Orientation
It appears in every job ID.
verticaldefault
horizontal
States
rest
Shown in job IDs.
described
- No spaces.
invalid
Locked during a run.
disabled
Usage
When to use it
- Use
- Any Input, Textarea, Select, Checkbox, Switch or Slider that a person fills in or sets.
- Use
- Several related questions share one title (FieldSet and FieldLegend).
- Use
- A set of fields is submitted together and checked together (Form).
- Not for
- A search box that filters the page, labelled by the page itself: give the Input aria-label.
- Not for
- A value to read, not to change: show it as text, or Input mode="copy".
Rules
9 rules
- Must
- Put exactly one control in a Field; group several with FieldSet. Because Base UI binds the label, the description and the error to one control, so a second control is named by the first one's label.
- Never
- Let a placeholder stand in for FieldLabel. Because a placeholder vanishes on the first keystroke and is not a reliable accessible name.
- Must
- Write FieldLabel in sentence case, a noun for the value, with no colon; it sets the capitals. Because the label role uppercases it on screen while a screen reader reads the source, and typed capitals are spelled out.
- Must
- Say in FieldError what is wrong with this value and how to fix it, in one sentence. Because the red edge only says something is wrong; the sentence is what a screen reader hears and what the person acts on.
- Must
- Validate through the Field (validate, invalid or the control's constraints), never with your own onChange check. Because Field waits for blur before it shows an error and then clears it on the keystroke that fixes it, and a hand check shows red on the first letter.
- Never
- Mark a required field with a red asterisk; pass required or optional to FieldLabel. Because red means something went wrong in Sodium, and an asterisk is a symbol a screen reader may skip.
- Should
- Mark whichever kind is rarer in the form: optional when most fields are required, required when most are optional. Because a word on every label is noise, and the few marked ones stand out.
- Must
- Route server errors back through Form errors by field name, and announce the result in FormStatus. Because Form focuses the first invalid field and Base UI ties the message to it, where a toast leaves the person hunting for the field.
- Should
- Use orientation="horizontal" with FieldContent for a switch or a checkbox beside its label and description.
State order
4 states, highest first
- 1
- disabled
- 2
- invalid
- 3
- described
- 4
- rest
Accessibility
6 checks
- FieldLabel is a <label> bound to the control; FieldDescription and FieldError join its aria-describedby.
- The label's capitals come from CSS, so a screen reader reads the sentence-case source.
- FieldError appears when the field is invalid and is read with the control on focus; the control gets aria-invalid.
- FieldSet is a <fieldset> named by its <legend>, so each control inside is announced with the set's title.
- Form focuses the first invalid field on submit; FormStatus is role="status", rendered from the start so its change is heard.
- The label and description are text-2, 7.8:1 on the page; the error word is --fail-text, 6.5:1.
Keyboard
2 keys
- Tab
- Moves from field to field; the label and description are not stops.
- Enter
- In a text field, submits the Form.
Edge cases
7 edge cases
- Error longer than the field
- Wraps under the control up to the 60ch hint measure.
- Several schema errors
- Duplicates drop and the rest become a list.
- Field inside a Field
- Development builds warn; the inner control would take the outer label.
- Description outside a Field
- Renders a plain paragraph, so it works under a FieldLegend.
- Long label
- Wraps at any character, so a long mono label never pushes the field wider.
- Phone width
- A responsive field stacks its label above the control.
- Submit twice while pending
- Form drops the second submit, Enter in a field included.
API
9 props
Field orientation'vertical' | 'horizontal' | 'responsive'default'vertical'Field validate, invalid, nameBase UI FieldField validationMode'onBlur' | 'onChange' | 'onSubmit'FieldLabel required, optionalbooleandefaultfalseFieldError errorsArray<{message?: string}>FieldSet disabledbooleandefaultfalseFieldLegend variant'legend' | 'label'default'legend'Form pending, errors, onFormSubmitboolean, Record<string, string>, (values) => voidFormStatus status'ok' | 'fail'
Tokens
15 tokens
--text-1- #161512
--text-2- #55524a
--text-3- #6b675e
--text-disabled- #a8a499
--fail-text- #b3261e
--ok-text- #2c6a3a
--line- #e2dfd5
--type-label-sm- 400 12px/16px var(--font-mono)
--type-caption- 400 13px/18px var(--font-sans)
--type-heading-sm- 400 18px/1.3 var(--font-sans)
--type-micro- 400 11px/14px var(--font-mono)
--measure-hint- 60ch
--label-col- 160px
--space-4- 16px
--space-6- 24px