Components · Inputs
Label
BetaNames a form control.
- Source
components/ui/label.tsx - shadcn/ui Label
- Figma: not linked yet (Q13)
When to use
- For every form control: inputs, textareas, selects, checkboxes, radios, switches, sliders and OTP fields. Each one has a visible label.
When not to use
- For a group of controls (radio buttons, a set of checkboxes): name the group with a
fieldsetandlegend, and use a label for each option. - For headings or help text: use text styles. A label is tied to one control.
- For icon-only buttons: they use
aria-label, since there is no visible text to link.
Anatomy
- 1. Label text: names the value, 14px medium
- 2. Optional hint (optional): in muted text, inside the label
- 3. The control it is linked to with htmlFor and id
Variants
Above a field
Beside a control
| Placement | Use for |
|---|---|
| Above the field | Text fields, textareas, selects, OTP fields. The label and field are a grid gap-2. |
| Beside the control, after it | Checkboxes, switches and radio options. The control comes first (at the start), the label after it, gap-2. |
| With an "Optional" hint | Forms where most fields are required: mark the few that aren't, in text-muted-foreground inside the label, so it is read with the name. |
States
| State | What changes | Token |
|---|---|---|
| Default | Medium weight, 14px, no line-height padding | text-sm, font-medium, leading-none |
| Disabled, control before it | Half opacity, not-allowed cursor. Needs the control to have the peer class (Checkbox and Switch do) | peer-disabled:opacity-(--opacity-disabled) |
| Disabled, control after it | Half opacity. Wrap label and field in an element with group and data-disabled="true" | group-data-[disabled=true]:opacity-(--opacity-disabled) |
The "Include cardio" checkbox above shows the first case; the disabled field in Textarea states shows the second.
There is no invalid style on the label: the field's border and the error message below it carry the error, so the label stays readable.
Usage guidelines
- Always link with
htmlForandid, usinguseId()so ids never collide. Clicking the label then focuses or toggles the control. - Keep the label outside the field. Don't use placeholders as labels.
- Don't put links or buttons inside a label; clicking them would also activate the control.
Content guidelines
- A noun or short noun phrase: "Client email", "Program name", "Body weight (kg)". Units go in brackets.
- Sentence case, no colon, no ending period.
- For checkboxes and switches, a statement that is true when on: "Include rest days".
- Arabic labels are nouns too, with units in Arabic: "وزن الجسم (كغ)"، "اسم البرنامج".
Accessibility
| Key | Does |
|---|---|
| None | A label isn't focusable. Clicking it focuses or toggles its control |
- Renders a native
<label>(Radix Label, which also stops a double-click on it from selecting text). - The label becomes the control's accessible name: "Client email, edit text" or "Include rest days, checkbox, checked".
- An "Optional" hint inside the label is read as part of the name: "Discount code Optional, edit text".
- A required field uses the
requiredattribute on the control, so it is announced as "required". Don't rely on an asterisk alone.
RTL
- Text aligns to the start; there is nothing to mirror.
- A checkbox or switch comes first in the markup, so it sits at the right in RTL with the label to its left.
- An "Optional" hint follows the label in reading order (to its left in RTL), because the label is a flex row with
gap-2. - Email addresses and codes in fields stay left to right with
dir="ltr"on the input, as in the first example.
Tokens used
Read from components/ui/label.tsx at build time, so this list changes when the component does. Opacity modifiers such as /90 are shadcn hover and focus tints on top of the token.
| Token | Utilities | SuperCoach | Coach |
|---|
- Opacity
opacity-(--opacity-disabled) - Type
font-medium - Type
leading-none - Type
text-sm
Props
<Label>
Also takes every prop of Radix Label.Root
No props of its own.
Replaces in coach-admin
From the read-only audit of coach-admin: 25 style values, 52 uses.
coach-admin styles bare label elements globally, plus Bootstrap's .control-label and Element UI's .el-form-label. Many screens also have their own one-off label classes (such as .switch-label or .meal-add-bulk-label), which are not listed here because they are part of larger components.
Classes and selectors
label29.control-label8.el-form-label7.label6label::before2
SCSS variables in these styles
$black-text-color→--foreground