Skip to content

Field

Lays out a form control with its label, help text and error.

Library
What’s this?

Use the name on the contract.

Installation

pnpm dlx shadcn@latest add @wisty/field

The CLI installs the Radix or Base UI file to match your project, with what it builds on: label, separator.

If your project doesn't have Wisty UI's theme yet, add it once with npx shadcn@latest add @wisty/cosmos. Until then, components keep shadcn's default look. Installation has the details.

When to use

Use it

  • A form control needs a label, and maybe help text or an error. It does what a Lightning input's label, help text and error do, for any control.
  • Several fields make up a form, or related fields need a legend, like an address.
  • A checkbox, radio or switch needs its label beside it.
  • It works with any form library.

Don't use it

  • A control needs only a label, outside a form. Label is enough.
  • You show a record's values read-only. Use Output field, or Record detail for a record's whole Details tab.
  • The message is about the whole form, not one field. Use Alert above the form.

Usage

A field holds one control with its label and text:

Field
├── FieldLabel
├── control, like Input
├── FieldDescription
└── FieldError

Related fields share a legend:

FieldSet
├── FieldLegend
├── FieldDescription
└── FieldGroup
    ├── Field
    └── Field
import { Field, FieldDescription, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
<Field>
  <FieldLabel htmlFor="phone">Phone</FieldLabel>
  <Input id="phone" type="tel" aria-describedby="phone-help" />
  <FieldDescription id="phone-help">Include the country code.</FieldDescription>
</Field>

For a text field with its label in a column beside it, as a record's edit form lays them out, give Field layout="horizontal". From a 48rem screen the label takes the first third, less a gap, and the control and help text start after it; below that the field stacks. layout="auto" follows Salesforce's display density: stacked, and horizontal when the page is compact (data-density="compact" on <html>, see Theming).

For help that opens from an info button beside the label, as Salesforce's field-level help does, put a TooltipTrigger after the FieldLabel with the help in its TooltipContent, as the Label with help example shows. Name the button "Help for" and the label, and point its aria-describedby at a hidden copy of the help inside it. In Base UI projects the tooltip doesn't describe its trigger, and in Radix projects it does only while open.

For a checkbox, radio or switch, give Field orientation="horizontal" so the label sits beside the control. When it also has a description, wrap the label and description in FieldContent, as the Checkbox group example shows.

For a form library's errors, mark the Field with data-invalid, set aria-invalid on the control and pass the list to FieldError. One message shows as text, several as a list, each once:

<Field data-invalid={invalid}>
  <FieldLabel htmlFor="email">Email</FieldLabel>
  <Input id="email" aria-invalid={invalid} aria-describedby="email-error" />
  <FieldError id="email-error" errors={errors} />
</Field>

Examples

Fieldset

A billing address in a `FieldSet` under a `FieldLegend` and a description, then a labelled `FieldSeparator` before an optional field.

Billing address

Where we send invoices.

Optional

Checkbox group

Three checkboxes in `orientation="horizontal"` fields under `FieldLegend variant="label"`, stacked tight as SLDS does, one with a description.

Notify me about

A summary of your team's open cases, every Monday.

Label beside the field

A contact's fields with `layout="horizontal"`: each label in a column, help text under its input. Below a 48rem screen they stack.

Include the country code for numbers outside the US.

Label with help

An info button after the `FieldLabel` that shows the field's help in a `Tooltip` and describes itself with it, through `aria-describedby`.

API reference

PartBuilt on
FieldSet<fieldset> (opens in a new tab)
FieldLegend<legend> (opens in a new tab)
FieldGroup<div> (opens in a new tab)
Field<div> (opens in a new tab)
FieldContent<div> (opens in a new tab)
FieldLabelLabel
FieldTitle<div> (opens in a new tab)
FieldDescription<p> (opens in a new tab)
FieldSeparator<div> (opens in a new tab)
FieldError<div> (opens in a new tab)

FieldLegend

PropTypeDefault
variant"legend" | "label""legend"

Field

PropTypeDefault
orientation"vertical" | "horizontal" | "responsive""vertical"
layout"stacked" | "horizontal" | "auto""stacked"

FieldError

PropTypeDefault
errorsArray<{ message?: string } | undefined>

SLDS mapping

  • Field is slds-form-element; FieldGroup stacks fields as slds-form-element_stacked does. layout="horizontal" is slds-form-element_horizontal.
  • FieldLabel is slds-form-element__label, through Label. Beside a checkbox or radio it's regular weight, as SLDS's are.
  • FieldDescription is slds-form-element__help. FieldError is the help text of an slds-has-error form element; the control draws its own error style from aria-invalid.
  • FieldSet is a fieldset.slds-form-element, FieldLegend is slds-form-element__legend.

Known gaps:

  • FieldSeparator, and the selectable card a FieldLabel becomes when it wraps a Field, have no SLDS counterpart.
  • Read-only and inline-edit form elements are Output field's, not Field's.
PropValueSLDSNotes
orientationverticalslds-form-element slds-form-element_stackedThe label above the control.
orientationhorizontalslds-checkbox, slds-radioThe control beside its label, as SLDS lays out checkboxes and radios. For a label beside a text control, use layout="horizontal".
orientationresponsivenoneVertical, then horizontal when the field group is at least 28rem wide.
layoutstacked (added)slds-form-element_stackedThe label above the control. The default; shadcn's own layout.
layouthorizontal (added)slds-form-element_horizontalA text field with its label in a column, from a 48rem viewport. Applies to a vertical field.
layoutauto (added)slds-form-element_stacked, or slds-form-element_horizontal in compact densityStacked, and horizontal when the page is compact (data-density="compact"), as Lightning's display density lays out record fields.
FieldLegend variantlegendslds-form-element__legend
FieldLegend variantlabelslds-form-element__legend slds-form-element__label

Accessibility

  • Link each label to its control with htmlFor and id, and help text and errors with aria-describedby. Field doesn't do it for you.
  • Set aria-invalid on the invalid control. FieldError has role="alert", so its message is announced when it appears.
  • Mark a required field with required on the control and an asterisk in the label, as the Account details example shows.
  • In Cosmos dark, text in an invalid input is about 4.3:1 against its background, below AA. Salesforce's own stylesheet fails the same way; the error text below the field passes.

Responsive behavior

  • orientation="responsive" turns horizontal once the surrounding FieldGroup is at least 28rem wide. It reads the group's width, so outside a FieldGroup it stays vertical.

Rules

  • One Field per control, with one FieldLabel.
  • Use orientation="horizontal" only for checkboxes, radios and switches. For a text field with its label beside it, use layout="horizontal", or layout="auto" to follow the page's density; both need the default vertical orientation.
  • Don't add spacing classes between fields. FieldGroup spaces them.
  • A group of checkboxes takes FieldLegend variant="label" and data-slot="checkbox-group" on its FieldGroup, as the Checkbox group example shows. Without the slot, the boxes sit as far apart as text fields.
  • Don't color the label of an invalid field. Only the error text and the control turn red.