Skip to the content

Kongens Nytorv

Metro M1, M2 and M3.

The map shows the stops near you

Props

NameTypeDefaultDescription
label*ReactNode—Required. The field's name, in sentence case, such as "Stop name": shown above the control, and the control's accessible name.
hiddenLabelbooleanfalseWhether the label is heard but not seen. Use it only where the screen around the field already says what it is for.
optionalbooleanfalseWhether the person may leave the field empty. Adds "(optional)" after the label's words, seen and heard as part of the control's name. Set it on the few fields a form doesn't ask for; Field draws no mark for a required one.
optionalLabelstringThe locale'sOverrides "(optional)", the mark after the label's words with optional.
descriptionReactNode—A line of help under the label, such as "As written on the stop sign", read after the label by a screen reader. Left out, no description is rendered.
errorReactNode—What is wrong with the value and how to put it right, such as "Enter a stop name". Given, it marks the field invalid and is shown under the control; left out, the field shows Base UI's own message when the control fails its checks.
children*ReactNode—Required. The control the field labels: a control built on Base UI, which registers with the field, such as a TextField's box.
refRef<HTMLDivElement>—Reaches the root, the Field.Root <div>.
slotProps{ label?: FieldLabelProps | undefined; description?: FieldDescriptionProps | undefined; error?: FieldErrorProps | undefined; }—Props for each part: label, description, error.
label (required)ReactNode, default —
Required. The field's name, in sentence case, such as "Stop name": shown above the control, and the control's accessible name.
hiddenLabelboolean, default false
Whether the label is heard but not seen. Use it only where the screen around the field already says what it is for.
optionalboolean, default false
Whether the person may leave the field empty. Adds "(optional)" after the label's words, seen and heard as part of the control's name. Set it on the few fields a form doesn't ask for; Field draws no mark for a required one.
optionalLabelstring, default The locale's
Overrides "(optional)", the mark after the label's words with optional.
descriptionReactNode, default —
A line of help under the label, such as "As written on the stop sign", read after the label by a screen reader. Left out, no description is rendered.
errorReactNode, default —
What is wrong with the value and how to put it right, such as "Enter a stop name". Given, it marks the field invalid and is shown under the control; left out, the field shows Base UI's own message when the control fails its checks.
children (required)ReactNode, default —
Required. The control the field labels: a control built on Base UI, which registers with the field, such as a TextField's box.
refRef<HTMLDivElement>, default —
Reaches the root, the Field.Root <div>.
slotProps{ label?: FieldLabelProps | undefined; description?: FieldDescriptionProps | undefined; error?: FieldErrorProps | undefined; }, default —
Props for each part: label, description, error.

Use it

import { Field } from '@mylder/perron'

Ask your agent

get_reference({ library: "base-ui", component: "Field" })

Keyboard and ARIA

From the Base UI reference for Field and the installed FieldRoot, FieldLabel, FieldDescription and FieldError. Field adds no keys: every key is the control's.

KeyDoesFrom
Tab, Shift+TabMove focus to and from the control, the field's one tab stop; the label, description and error take noneBase UI
A press on the labelFocuses the control: natively through htmlFor, or through Base UI's own handler for a hidden labelBase UI
ElementRoleAccessible name fromStates announced
rootnone: a <div>nonenone
labelnone: a native <label>, or a hidden spanIts text: the caller's label, then "(optional)" with optionalnone
The controlThe control's ownaria-labelledby the label, and its native label through htmlFor, so "Stop name (optional)" with optionalaria-describedby the description and the mounted error, aria-invalid while invalid and not disabled, disabled
descriptionnone: a <p>noneRead as the control's description
errornone: a <div>noneRead as the control's description while it is mounted

The error stays a plain <div>, read through the control's aria-describedby, with no live region of Field's own. Base UI mounts the error only with its message, and a live region inserted with its content is not reliably announced; a role="alert" would interrupt on every keystroke with validationMode="onChange"; and the person hears the error when focus reaches the control, as Base UI's Form moves focus to the first invalid control on submit.

What axe won't catch, from the contract, each with how this component meets it:

  • Everything the eye is told, the ear is told, for every shape each prop accepts: the label names the control, even hidden, and the optional mark is inside it, so the ear hears "(optional)" in the control's name; the description and the error are the control's aria-describedby, so the ear hears both with the control; an invalid field is aria-invalid and its error is words, never only the control's red edge.
  • Every landmark and named region has an accessible name: none here; Field is not a landmark, and a group of fields is a Fieldset's to name.
  • Every default label can be overridden: optionalLabel overrides "(optional)", Field's one owned string (see Owned strings).
  • Every shape the type accepts renders, in every variant: label, description and error render a string, an element and a list alike; a long Danish compound wraps in each (CR-8); Base UI's several messages render as a list.
  • A hidden copy kept for animation is aria-hidden, and a collapsed region is inert: none here; the error is unmounted while the field is valid, and the description while it is not given.
  • Native semantics first: a native <label> with htmlFor, a <p> for the description, and the control's own semantics; Perron adds no ARIA, and Base UI only aria-labelledby, aria-describedby and aria-invalid.
  • Focus moves in reading order and returns on close: the control is the field's one tab stop, and the label, description and error sit around it in reading order; nothing opens or closes.
  • Every target is at least size.target-min square: the control's, which is the control's own; the label is a larger target for the same control, with no size of its own to meet.
  • Loops stop when the system asks for less motion: none here; Field has no loop and no transition (CR-9).

Owned strings

KeyEnglishOverrideSeen or heard where
optional"(optional)"optionalLabeloptional, seen after the label's words with optional, and heard in the control's name, as "Stop name (optional)"

optional is new, described in en.ts as A field's label: after the words of a field the person may leave empty, as in "Stop name (optional)"., with the Danish, Swedish and Norwegian written by the build. It is lowercase in its brackets, since it follows the label's words rather than starting a sentence, as Content design's sentence case reads.

Every other word is the caller's, through label, description and error, or Base UI's message for a failing check, which is the caller's validate result or the browser's own.

Field marks an optional field, never a required one. optional (default false) adds the owned "(optional)" after the label's words, inside the label element, in color.text.secondary, so it is part of the control's name for the ear as well as the eye; optionalLabel overrides it on one instance. Most fields in a form are asked for, so the few that aren't carry the mark, and the words need no legend, where an asterisk does. Field can't read required, which is the control's prop, so it draws no required marker: TextField, Select and the other dependents take optional and pass it through, and a screen whose label already says it writes nothing more.

Field keeps Base UI's showing of the browser's own message for a failing native check, such as required, when the caller gives no error, as a known exception to the owned strings. The browser writes that message in its own interface language, which may not be PerronProvider's; owning one string per check would take a new key for each of the ten native checks for messages a screen should word for its own field ("Enter a stop name", not "Please fill in this field"); a caller who wants the field's own words gives error, or slotProps.error.match with its own children; and the message appears only after a check fails in the browser, never in the server-rendered markup the contract story's owned-strings check reads.

Do and don't

For a caller using the component, with the reason. Each row is a rule: a must row's Don't is never right, a should row's needs a reason, and Checked by says what catches the Don't in a caller's code.

RuleLevelDoDon'tChecked by
DD-1mustUse a field component that composes Field, such as TextField or Select, where there is oneWrap such a component in Field again: it already has its label, and the control would be named twicereview
DD-2mustPut a control built on Base UI inside, which registers with the fieldPut a plain <input> inside: it gets no htmlFor, aria-labelledby or aria-describedby, so it is unnamed for the ear (CR-10)review
DD-3mustGive a label that names the value, "Stop name", and hide it with hiddenLabel only where the screen already says itLeave the field without a label, or let a placeholder stand in for one: it vanishes as the person typesreview
DD-4mustWord an error as what to do, "Enter a stop name"Blame the person ("You forgot the stop") or say only that it failed ("Invalid input"), against Content designreview
DD-5mustGive error whenever the field is invalidSet invalid with no message: the control's red edge alone tells only the eye, and only by its colourreview
DD-6shouldPut help the person needs while typing in description, such as "As written on the stop sign"Put the help in the error: it appears only after a mistakereview
DD-7mustSet optional on the few fields the person may leave empty, and leave the rest unmarkedWrite "(optional)", "(required)" or an asterisk into label yourself: it misses the locale, reads twice beside Field's mark, and an asterisk needs a legendreview
DD-8shouldLabel a checkbox or a switch beside it, by its own labelUse Field for a checkbox or a switch: Field's label sits above the control, where theirs sits beside itreview