Field
fieldComposes labels, controls, help text, validation messages, and required state, stacked vertically or side by side.
Usage
Basic usage
label string Field.Label, children is the control (Input / Textarea).
<Field label="Email">
<Input placeholder="you@work.com" />
</Field>Help instructions
description renders muted small characters and automatically strings aria-describedby.
We will not publish your email address
<Field label="Email" description="We will not publish your email">
<Input placeholder="you@work.com" />
</Field>Error status
If error is not empty, it implies invalid (marked red + shows error), and there is no need to pass invalid separately.
<Field label="Email" error="The email format is incorrect">
<Input defaultValue="not-an-email" />
</Field>Required
required draws a red asterisk before the label and injects aria-required into the control. Validation still lives in the rules; this prop performs no validation.
<Field label="banner type" required>
<Input placeholder="Select an option" />
</Field>Horizontal settings row
orientation=horizontal puts the label area on the left, the control on the right, and the error message on its own full-width row.
Pick your preferred color scheme
<Field
orientation="horizontal"
label="Theme"
description="Pick your preferred color scheme"
>
<Input defaultValue="Dark" />
</Field>Horizontal with a fixed label column
Override the default column template to get a fixed label column and a control that fills the rest; no extra prop is needed.
<Field
orientation="horizontal"
label="Email"
error="The email format is incorrect"
className="grid-cols-[6rem_1fr]"
>
<Input defaultValue="not-an-email" />
</Field>Disabled
disabled is passed to Field.Root, which disables the control.
<Field label="Email" disabled>
<Input placeholder="you@work.com" />
</Field>When to use
Use Field to associate one control, such as Input or Textarea, with a label, supporting description, and validation error. Field wires those elements together with aria-describedby and aria-invalid. Form and ProForm use it internally; it is also suitable for custom form rows and controls inside StepsForm.
Import
import { Field } from "@hulianui/ui"Props
| Name | Type | Default | Description |
|---|---|---|---|
| invalid | boolean | false | Explicit invalid state; a nonempty error also marks the field invalid. |
| required | boolean | false | Required state: renders a red asterisk before the label and injects aria-required into the control. It performs no validation (rules remain the only source of validation) and exists so users can see which fields are required before submitting. register() from useForm derives required from the rules, so it can be forwarded directly. |
| requiredMark | boolean | ReactNode | true | Shape of the required marker. false keeps aria-required without drawing a marker; a ReactNode replaces the default asterisk. Ignored when required is falsy. |
| disabled | boolean | false | Disables the field. |
| name | string | - | Field name forwarded to the underlying Field.Root. |
| orientation | "vertical" | "horizontal" | "vertical" | Layout direction. horizontal places the label area on the left, the control on the right, and the error message on its own full-width row, which is the one-setting-per-row layout of a settings page. ARIA wiring and error rendering are identical in both directions. |
| colSpan | "full" | - | Spans the full row in a ProForm column grid; has no effect outside that grid. |
| className | string | - | Additional class name for the Field.Root container, which is a flex column when vertical and a two-column grid when horizontal. |
| labelClassName | string | - | Appended to the label, whose default is text-sm font-medium text-foreground w-fit. Classes are merged with twMerge, so passing text-xs overrides the default size and w-full restores a full-width label. |
| descriptionClassName | string | - | Appended to the description, whose default is text-xs text-muted-foreground. |
| errorClassName | string | - | Appended to the error message, whose default is text-xs text-danger. |
Slots
| Slot | Type | Description |
|---|---|---|
| children* | ReactNode | Field control, such as HulianUI Input or Textarea. |
| label | ReactNode | Visible field label. |
| description | ReactNode | Help text. |
| error | ReactNode | Validation message. Any nonempty value marks the field invalid and renders the error. |
Usage guidelines
requiredcan injectaria-requiredonly when `children` is a single element, since that is the only node Field can reach. When children is a fragment (control plus a button) or plain text, setaria-requiredon the control yourself; otherwise assistive technology never learns the field is required, because a decorative asterisk isaria-hidden.aria-requiredis only valid on input-like roles (textbox, combobox, listbox, radiogroup, checkbox, …). When the control's focusable element is arole="button"(the dropzone of Upload being the typical case), injecting it changes nothing for screen readers, so that class of component translates the required state into a description itself. Usage does not change.- The label shrinks to its text by default (
w-fit). It is a real<label>withhtmlFor, so when flex stretches it across the row, the invisible space after the text still forwards clicks to the control. For overlay controls that reads as "the dropdown opened out of nowhere when I clicked above it". PasslabelClassName="w-full"when you need a full-width label, for example to push a switch to the far right. - Do not wrap the label in a hand-rolled
RequiredLabeljust to draw an asterisk: that marks the field for sighted users only, and every page ends up with a different asterisk position and color. - A non-empty
erroralready impliesinvalid; do not pass both. Passinvalidalone only when the control needs invalid styling without an error message. - Field uses Base UI Field and renders externally controlled errors with
match={true}. Keep the error inside Field so it remains part of the generatedaria-describedbyrelationship; a separate<p>will not be connected automatically. See [[base-ui-field-error-match-true-for-external-controlled-error]]. - For a Textarea child, follow the render-as typing guidance in [[base-ui-field-control-render-textarea-type-safe]].
- There is no separate prop for the horizontal label column width. With
orientation="horizontal"theField.Rootis agrid-cols-[1fr_auto]grid, so passclassName="grid-cols-[8rem_1fr]"to override the column template. The defaultautocolumn keeps the control flush right, which suits settings rows;1frlets the control fill the remaining width, which suits form rows. - When you only need a label, without the help text, error message, and ARIA wiring, use Label rather than wrapping an empty Field just to borrow the label styling.
Related
Label · Form · ModalForm / DrawerForm · ProForm · StepsForm · LoginForm · SearchForm
Playground
We will not publish your email address
<Field label="Email" description="We will not publish your email address">
<Input placeholder="you@work.com" />
</Field>