Skip to content
SuperCoach

Components · Inputs

Label

Beta

Names a form control.

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 fieldset and legend, 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. 1. Label text: names the value, 14px medium
  2. 2. Optional hint (optional): in muted text, inside the label
  3. 3. The control it is linked to with htmlFor and id

Variants

Above a field

Beside a control

PlacementUse for
Above the fieldText fields, textareas, selects, OTP fields. The label and field are a grid gap-2.
Beside the control, after itCheckboxes, switches and radio options. The control comes first (at the start), the label after it, gap-2.
With an "Optional" hintForms 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

StateWhat changesToken
DefaultMedium weight, 14px, no line-height paddingtext-sm, font-medium, leading-none
Disabled, control before itHalf opacity, not-allowed cursor. Needs the control to have the peer class (Checkbox and Switch do)peer-disabled:opacity-(--opacity-disabled)
Disabled, control after itHalf 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

Do.A visible label that says what to enter, linked to the field.
Calories
Don't.Text that looks like a label but isn't linked. Screen readers announce an unnamed field, and clicking the text does nothing.
  • Always link with htmlFor and id, using useId() 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

KeyDoes
NoneA 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 required attribute 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.

Semantic color tokens used by this component
TokenUtilitiesSuperCoachCoach
  • Opacityopacity-(--opacity-disabled)
  • Typefont-medium
  • Typeleading-none
  • Typetext-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
  • .label6
  • label::before2

SCSS variables in these styles

  • $black-text-color→ --foreground

Input, Textarea, Checkbox, Switch, Form.