Label
Names one form control. Put it above an input or select, wrap a checkbox, switch, or radio with it, or place it beside a long confirmation.
Above a control
htmlFor names an input, select, or textarea. A click on the label moves focus to the control.
Compact filters
The same label over 28px select triggers in a files toolbar.
Wrapping a checkbox
Put the checkbox first, then its text. The whole row toggles it, and the text dims when the checkbox is disabled.
Wrapping a switch
Both switch sizes keep the 8px gap and the 14px label text.
size="default"18px track · settings rowssize="sm"14px track · dense listsWrapping a radio
Each option is a label around its radio. Arrow keys move between options.
Checkbox before a label
For long confirmations, place the checkbox beside the label and point htmlFor at its id.
Visually hidden text
In a grid of checkboxes, the label can hold only the checkbox and hidden text that names the row.
| Person | Use | Manage |
|---|---|---|
| Maya Chen | ||
| Jordan Okafor | ||
| Priya Raman-Lindqvist |
Wrapping a text control
A label around a textarea stacks the text above it, so no id is needed.
Naming a custom control
When the control is not a form element, give the label an id and point aria-labelledby at it.
Inside a locked field
A field wrapper with data-slot="field" and data-disabled dims its labels and stops label clicks while a save runs.
Usage
import { Label } from "@tulipfarm/sprout/label";
<div className="grid gap-1.5">
<Label htmlFor="workspace-name">Workspace name</Label>
<Input id="workspace-name" />
</div>
<Label>
<Checkbox checked={business} onCheckedChange={setBusiness} />
Shared business account
</Label>
<div className="flex items-start gap-3">
<Checkbox id="retained-data" checked={acknowledged} onCheckedChange={setAcknowledged} />
<Label htmlFor="retained-data">
I understand that workspace data is retained, not erased.
</Label>
</div>Label renders a label element and takes everylabel prop. Text is 14px, medium weight. Children sit in a row 8px apart, so a control and its text line up without extra classes. There is one size. It pairs with large and default inputs, 32px and 28px selects, and both switch sizes.
Long text wraps, and long names or addresses break anywhere instead of overflowing. When a checkbox, switch, or radio is inside the label or just before it, the line height grows to 20px and the pointer becomes a hand, since a click on the text toggles the control.
Wrapping a text control
<Label>
{advanced ? "Response JSON" : "Decision or comment"}
<Textarea value={text} disabled={closed} onChange={…} />
</Label>When the label wraps a textarea, select, input, or select trigger, the text stacks above the control with a 6px gap and the control fills the width. The control needs no id.
Disabled
Label has no disabled prop. It follows its control.
A label that wraps a disabled control turns muted and shows a not-allowed cursor. The control keeps its own disabled look, so nothing is dimmed twice.
A label just before or after a disabled control, such as a confirmation beside its checkbox or a stacked label over a disabled input, fades to 50%.
Inside a wrapper with data-slot="field" and data-disabled, or inside a disabled fieldset, the label fades to 50% and ignores clicks.
Accessibility
Every label must name a control. Use htmlFor with the control'sid, or wrap the control. Base UI checkboxes, switches, and radios take the id on their hidden input, so both forms work, and Space toggles the control once it has focus.
For a control that is not a form element, such as a rich text editor, give the label an id and set aria-labelledby on the control. A label with no control and no id names nothing.
When a grid of checkboxes has its names in row and column headers, wrap each checkbox and add visually hidden text, such as “Use Maya Chen”.
Label text cannot be selected, so a double click on it does not highlight words. Color and opacity changes take 120ms and stop when reduced motion is requested.
Theme tokens
Text uses --sprout-text, and --sprout-mutedwhen it wraps a disabled control. Size and family follow --sprout-text-sm and --sprout-font.