v0.5

Field

Layout wrapper that pairs a form control with its label, description, and error.

We'll never share your email with anyone.

Description

Field is the form-layout primitive of the design system. It renders a <div role="group"> and owns the shared context (size, orientation, invalid, disabled, loading) that every part inside it reads. It is a compound component: Field is the wrapper, and parts like FieldLabel, FieldDescription, FieldError, and FieldHelper slot inside it around a control.

Reach for it whenever a form control needs a label, helper text, or validation message. Wrap a single Input, Select, Textarea, Checkbox, Switch, or Slider in a Field so spacing, sizing, and error styling stay consistent. Use FieldGroup to stack several fields with even rhythm, and FieldSet with FieldLegend to label a related cluster (a set of checkboxes, a plan picker).

Don't use Field as the control itself. For the input, use Input; for the dropdown, use Select. For a multi-option group that shares one value, reach for RadioGroup or CheckboxGroup, which manage selection state. FieldSet groups form controls, not page sections; for page layout use your layout primitives.

Installation

pnpm dlx @create-ui/cli add field

Anatomy

Field sets the size and state context once; the parts inside it read that context instead of being sized one by one. FieldContent is optional and only needed when a label plus description sit beside a control (checkbox, switch) in a horizontal layout.

<Field>
  <FieldLabel />
  <FieldContent>
    <FieldLabel />
    <FieldDescription />
  </FieldContent>
  <Input />
  <FieldDescription />
  <FieldError />
  <FieldHelper />
  <FieldFooter />
</Field>

Group related fields, optionally under a legend:

<FieldSet>
  <FieldLegend />
  <FieldGroup>
    <Field />
    <Field />
  </FieldGroup>
</FieldSet>

Usage

import {
  Field,
  FieldDescription,
  FieldError,
  FieldGroup,
  FieldLabel,
} from "@/components/ui/field"
<Field>
  <FieldLabel htmlFor="email">Email</FieldLabel>
  <Input id="email" type="email" />
</Field>

Examples

Sizes

size is xs, sm, or md (sm is the default). It sets the density for the label, description, and the control inside, all from one prop on Field.

Minimal density for inline editing.

Compact density for dense tables.

Default density for most forms.

Orientation

orientation="vertical" stacks the label above the control. horizontal puts them on one row, which fits checkboxes and switches. responsive stacks on narrow containers and inlines once there is room.

Label and control stack in tight space and move onto one row once the container is wide enough.

Rich Label

FieldLabel accepts the Label parts as children: LabelIcon, LabelRequired, LabelOptional, and LabelBadgeSlot. Pair them with FieldHelper (which takes an icon) and FieldFooter for a supporting link.

We'll never share your email with anyone.

We send a one-time verification link.

Validation

Set invalid on Field and add a FieldError. Pass a single message as children, or hand FieldError an errors array and it renders a deduped bulleted list. Wire aria-invalid on the control so assistive tech announces the state.

Composition

Field works the same around any control. One size on each Field cascades to the Input, Select, Textarea, or Switch it wraps, so you set density once per field.

Receive product news and occasional offers.

Rich Choice

For a checkbox or switch that carries an icon, a badge, a description, and a follow-up link, put the supporting content in FieldContent. Wrap the Label (with LabelIcon and LabelBadgeSlot) and its LabelDescription in LabelMain to keep them tightly grouped beside the control, then add a FieldFooter for the link. Reach for Label + LabelDescription here rather than FieldLabel + FieldDescription, since LabelMain is what binds a title to its description.

Choose the type of content you'd like to see across Create UI.

Grouping

FieldSet with FieldLegend variant="label" labels a cluster of related controls. Nest a FieldGroup inside to keep the spacing even.

Preferences

Select all that apply to customize your experience.

Separator

FieldSeparator draws a divider between fields. Pass children to label it (e.g. or) for alternative-input flows.

or

Accessibility

Field is a layout group, not a focus target. Focus lands on the control inside it; Tab moves between controls in source order.

KeyDescription
TabMoves focus to the control inside, then on to the next field.

ARIA notes:

  • Field sets role="group" and mirrors invalid, disabled, and loading to data-* attributes so descendants can style off the shared state.
  • Wire FieldLabel's htmlFor to the control's id so clicking the label focuses the control and screen readers announce the name.
  • FieldError renders with role="alert", so a newly shown error is announced. Set aria-invalid on the control to link it to the error visually and semantically.
  • FieldSet and FieldLegend render native <fieldset> / <legend>, which group the controls for assistive tech automatically.

Styling

Tailwind override: pass className to merge Tailwind classes with the component's CVA classes (via cn()):

<Field className="max-w-sm">…</Field>

Data slots and attributes: the parts set these for CSS targeting:

  • data-slot="field" on the Field root, with data-size, data-orientation, and data-invalid / data-disabled / data-loading when active.
  • data-slot="field-set" on FieldSet, data-slot="field-legend" on FieldLegend (with data-variant), data-slot="field-group" on FieldGroup.
  • data-slot="field-content" on FieldContent (with data-size).
  • data-slot="field-label" on FieldLabel and FieldTitle, data-slot="field-description" on FieldDescription.
  • data-slot="field-helper" on FieldHelper (with data-tone), data-slot="field-error" on FieldError, data-slot="field-footer" on FieldFooter (with data-size).
  • data-slot="field-separator" on FieldSeparator, data-slot="field-separator-content" on its inner label.

Target a specific state in CSS:

[data-slot="field"][data-invalid="true"] [data-slot="field-label"] {
  /* … */
}
  • Label: the standalone label and its parts (LabelIcon, LabelRequired, LabelBadgeSlot) that FieldLabel builds on.
  • Radio Group: use this for a set of mutually exclusive options that share one value.
  • Checkbox Group: use this for a set of independent toggles managed together.
  • Input / Select / Textarea: the controls a Field wraps; reach for them directly when you only need the control.

API Reference

Field

The wrapper that provides size and state context to every part inside it. Renders a <div role="group"> and extends Omit<React.ComponentProps<"div">, "size">, so standard div attributes (id, aria-*, etc.) pass through.

Props

PropTypeDefaultDescription
invalidboolean-Marks the field invalid; cascades to parts and sets data-invalid.
disabledboolean-Disables the field; cascades to parts and sets data-disabled.
loadingboolean-Marks the field loading; cascades to parts and sets data-loading.
classNamestring-Tailwind classes merged with the component's CVA classes via cn().
childrenReact.ReactNode-The label, control, and supporting parts.

Variants

VariantOptionsDefaultDescription
size"xs" "sm" "md""sm"Density; cascades to the label, parts, and the control.
orientation"vertical" "horizontal" "responsive""vertical"Layout of label and control. responsive stacks then inlines.

FieldGroup

Stacks several Fields with even spacing and provides a container-query context for responsive fields. Extends React.ComponentProps<"div">.

Props

PropTypeDefaultDescription
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-The Fields to stack.

FieldSet

Native <fieldset> wrapper for a related cluster of fields. Extends React.ComponentProps<"fieldset">, so disabled disables the whole set.

Props

PropTypeDefaultDescription
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-A FieldLegend and FieldGroup.

FieldLegend

Native <legend> for the FieldSet. Extends React.ComponentProps<"legend">.

Props

PropTypeDefaultDescription
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-The legend text.

Variants

VariantOptionsDefaultDescription
variant"legend" "label""legend"legend is the larger section title; label is tighter.

FieldLabel

The field's label. Extends Label (React.ComponentProps<typeof Label>) and reads size from Field context when not set. Accepts the Label parts (LabelIcon, LabelRequired, LabelOptional, LabelBadgeSlot) as children; see the Label component for their API.

Props

PropTypeDefaultDescription
htmlForstring-The id of the control this label describes.
size"xs" "sm" "md"-Override the inherited size. Rarely needed.
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-Label text and optional Label parts.

FieldTitle

A non-<label> heading for a field, used when the control is wrapped by an outer label (a checkbox card). Renders a <div> and extends React.ComponentProps<"div">.

Props

PropTypeDefaultDescription
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-The title text.

Variants

VariantOptionsDefaultDescription
size"xs" "sm" "md""sm"Type scale. Inherits from Field when unset.

FieldContent

Stacks a label and description beside a control in horizontal layouts. Renders a <div> and extends React.ComponentProps<"div">. Reads size from Field context for its gap.

Props

PropTypeDefaultDescription
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-A FieldLabel and FieldDescription.

FieldDescription

Supporting text below the label or control. Renders a <p> and extends React.ComponentProps<"p">. Tints to the error color when the Field is invalid.

Props

PropTypeDefaultDescription
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-The description text.

Variants

VariantOptionsDefaultDescription
size"xs" "sm" "md""sm"Type scale. Inherits from Field when unset.

FieldHelper

Inline helper row with an optional leading icon. Renders a <div> and extends React.ComponentProps<"div">. Defaults its tone to error when the Field is invalid.

Props

PropTypeDefaultDescription
iconReact.ReactNode-Leading icon rendered before the text.
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-The helper text.

Variants

VariantOptionsDefaultDescription
size"xs" "sm" "md""sm"Type and icon scale. Inherits from Field.
tone"neutral" "error""neutral"Color. Defaults to error when invalid.

FieldError

The validation message. Renders a <div role="alert"> and extends React.ComponentProps<"div">. Renders children if present, otherwise the errors array (deduped by message, as a bulleted list when there is more than one). Returns nothing when empty.

Props

PropTypeDefaultDescription
errorsArray<{ message?: string } | undefined>-Error objects to render when no children given.
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-An explicit error message, overrides errors.

Variants

VariantOptionsDefaultDescription
size"xs" "sm" "md""sm"Type scale. Inherits from Field when unset.

FieldFooter

A supporting action row, typically a link. Renders a <div> and extends React.ComponentProps<"div">.

Props

PropTypeDefaultDescription
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-The footer content, usually an <a>.

Variants

VariantOptionsDefaultDescription
size"xs" "sm" "md""sm"Type and icon scale. Inherits from Field.

FieldSeparator

A divider between fields, with an optional centered label. Renders a <div> and extends React.ComponentProps<"div">.

Props

PropTypeDefaultDescription
classNamestring-Tailwind classes merged via cn().
childrenReact.ReactNode-Optional label drawn over the divider.