|Kit

Field

Label, description, and error scaffold for any form control — built on Ark UI's Field, so the accessible name, description, and invalid state wire themselves to whatever control you nest inside.

Field is the one place the form family wires accessible names and descriptions. Wrap a field-aware control — the kit's Input, Select, Combobox, and the rest — and Ark UI hands it the right id, aria-describedby, aria-invalid, disabled, and required through context. No per-control plumbing, no manual htmlFor.

import { Field } from '@42-central/ui-react/field';
import { Input } from '@42-central/ui-react/input';

<Field label="Email" description="We'll never share it.">
  <Input placeholder="login@student.42.fr" />
</Field>
Most controls don't need this

Every control in the form family — TextInput, Textarea, Select, NumberInput and the rest — already carries label / description / error / required of its own, wired through this exact component. Reach for Field directly when you're composing something it doesn't cover: the bare Input shell, several controls sharing one label, or a control of your own.

Playground

Field

Loading preview

Props

Code

<Field
  label="Email"
  description="We'll never share it."
  size="md"
  placeholder="login@student.42.fr"
/>

Anatomy

The label binds to the control (click it to focus); the description renders above the control, between it and the label. An error renders below the control instead, independently of the description — set both at once and both stay visible.

We'll never share it.

Code

<Field
  label="Email"
  description="We'll never share it."
>
  <Input placeholder="login@student.42.fr" />
</Field>

Required

required sets the semantic flag (forwarded to the control) and renders a red asterisk in the label — the two always travel together.

Code

<Field label="Login" required>
  <Input placeholder="Pick your intra login" />
</Field>

Error

Passing error flips the field to invalid: the message renders below the control, is associated via aria-describedby, and any field-aware control inside turns red automatically — you don't set invalid on the control yourself. error renders independently of description — set both together and both stay visible, the description above the control and the error below it.

Set testId on the Field and it also derives `${testId}-error` on the rendered error text and `${testId}-description` on the rendered helper text — each only once that text is actually shown. See the Testing guide.

Enter a valid email address

Code

<Field label="Email" error="Enter a valid email address">
  <Input defaultValue="not-an-email" />
</Field>

Both description and error can be set at once — they occupy independent slots on either side of the control:

We'll never share it.
Enter a valid email address

Code

<Field
  label="Email"
  description="We'll never share it."
  error="Enter a valid email address"
>
  <Input defaultValue="not-an-email" />
</Field>

Sizes

size scales the field's own typography. Set the control's size to match — the family components forward a single size to both for you.

Code

<Field size="sm" label="Small"><Input size="sm" /></Field>
<Field size="md" label="Medium"><Input size="md" /></Field>
<Field size="lg" label="Large"><Input size="lg" /></Field>

Works with any field-aware control

Because the wiring rides on Ark's Field context, the same Field wraps every control in the family — Select, Combobox, MultiSelect, TagsInput, … — and each picks up the label, description, error, and state without extra props.

<Field label="Framework" description="Pick your stack" required>
  <Select data={['React', 'Vue', 'Svelte']} placeholder="Pick one" />
</Field>

<Field label="Tags" error="Add at least one">
  <TagsInput placeholder="Type and press Enter" />
</Field>

API

Prop

Type

Every other prop (including id) forwards to Ark UI's Field.Root. asChild isn't supported: the field renders its label, description and error around the control, which can't live inside one element.

Accessibility

  • The <label> is associated with the control automatically — clicking it focuses the control, and assistive tech announces the name.
  • A composite control (the kit's SegmentGroup and TimeInput) has no single element to focus, so its label is plain text with no for; the control's group takes the label as its name through aria-labelledby.
  • description and error are linked through aria-describedby, so both are read out with the control. error additionally sets aria-invalid.
  • required, disabled, and readOnly propagate to field-aware controls through Ark's Field context — set them once on the Field.
  • RTL: the asterisk uses logical spacing (margin-inline-start) and the layout is a plain column, so everything mirrors correctly under dir="rtl".

Changelog

v0.19.0
  • Field takes composite for controls with no single labelable element: the label becomes a span and the control is named through aria-labelledby

    #329
v0.18.0
  • asChild is a compile error on CircularProgress, Progress, Rating, Slider, Divider, Field, InputBase and PillsInput

    #294
v0.6.0
  • The description sits above the control, and the error shows independently of it

    #101
v0.5.1
  • Field's label names the real control through aria-labelledby

    #77
v0.3.0
  • Title's dark-mode color and Field's label color follow the Figma text tiers

    #35
v0.0.1
  • Input, Field, PillsInput and Pill: the shared input shell, label/help/error wrapper and chips

On this page