Skip to content
SuperCoach

Components · Actions

Toggle

Beta

A two-state button, such as marking a set as done.

Barbell back squat

4 sets × 6 reps

When to use

  • To turn one option on or off where it sits, with the result visible right away: favorite an exercise, link an exercise into a superset, show the rest timer.
  • In toolbars, where a button-shaped control fits better than a switch.

When not to use

  • For a setting with a label that saves immediately ("Check-in reminders"): use a Switch. A switch reads as a setting, a toggle as a tool.
  • As part of a form that is saved later: use a Checkbox.
  • To pick one of several options: use a Toggle group.
  • To start an action ("Duplicate"): use a Button. A toggle stays pressed; a button doesn't.

Anatomy

  1. 1. Container: transparent or outlined; filled with accent when on
  2. 2. Icon: 16px, aria-hidden
  3. 3. Label (optional): stays the same in both states

Variants

Default

Outline

VariantUse for
defaultInside a row or toolbar that already has a border: a favorite star on an exercise row.
outlineOn its own, where the control needs a visible edge to look clickable.

Icon-only or icon with label. Icon-only toggles need an aria-label, and the icon should change shape when pressed (an outlined star becomes a filled one), as in the first example.

States

Off
On
Disabled
StateWhat changesToken
OffNo fill (default) or an outline (outline)bg-transparent, border-input
HoverLight fillhover:bg-muted (default), hover:bg-accent (outline)
On (data-state="on")Accent fill and textbg-accent, text-accent-foreground
Focus-visibleRing around the togglering-ring/50, 3px
DisabledHalf opacity, no pointer eventsopacity-(--opacity-disabled)
Invalid (aria-invalid)Red border and ringborder-destructive, ring-destructive/20

The on-state fill (accent) is very close to the page background, so "on" is shown mostly by the text color. Pair it with a visible change in the icon (filled star, link icon) so the state doesn't depend on a faint fill. This is reported as a gap: see the Accessibility section.

Sizes

sm (32px) in dense tables and set loggers, default (36px) for most UI, lg (40px) on touch-first screens. All three meet the 24×24px minimum target. Heights come from the 4px spacing unit, not a sizing token (Q5).

Usage guidelines

Do.The label names the option. It stays the same when pressed; the pressed state says whether it is on.
Don't.A label that flips with the state. Screen readers hear 'Turn superset off, pressed' and users can't tell what it is now.
Do.A named setting that saves right away is a switch.
Don't.A toggle for an account setting. It looks like a button and doesn't say it is a setting.

Content guidelines

  • One to three words that name the option, not the action: "Superset", "Rest timer", "Show rest days".
  • Sentence case, no punctuation.
  • Arabic labels are nouns too: "مؤقت الراحة"، "مجموعة مركّبة".

Accessibility

KeyDoes
TabMoves focus to the toggle
Enter or SpaceTurns it on or off
  • Renders a <button> with aria-pressed. NVDA announces "Superset, toggle button, pressed" or "not pressed"; VoiceOver says "selected" for pressed.
  • The accessible name never changes with the state; only aria-pressed does.
  • Icon-only toggles need aria-label, written through the product's i18n so Arabic screens get an Arabic label.
  • The on state is bg-accent on the page background, about 1.1:1, so the fill alone doesn't meet the 3:1 non-text contrast a state indicator needs (WCAG 1.4.11). The text color change and an icon change carry the state today.

RTL

  • The icon sits before the label, so it moves to the right in RTL. Nothing else changes.
  • Icons in toggles are rarely directional; if one is (an arrow), mirror it with rtl:-scale-x-100.

Tokens used

Read from components/ui/toggle.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
--accentbg-accentbrand-50orange-50
--accent-foregroundtext-accent-foregroundbrand-700orange-700
--destructiveborder-destructive ring-destructive/20red-600red-600
--inputborder-inputneutral-200neutral-200
--mutedbg-mutedneutral-100neutral-100
--muted-foregroundtext-muted-foregroundneutral-600neutral-600
--ringborder-ring ring-ring/50brand-600orange-500
  • Opacityopacity-(--opacity-disabled)
  • Radiusrounded-md
  • Shadowshadow-xs
  • Typefont-medium
  • Typetext-sm

Props

<Toggle>

Also takes every prop of Radix Toggle.Root

Toggle props
PropTypeDefault
variant"default" | "outline""default"
size"default" | "sm" | "lg""default"

Replaces in coach-admin

From the read-only audit of coach-admin: 21 style values, 25 uses.

The only toggle buttons the audit found are the .tgl, .goal-toggle-btn and .sub-toggle-btn classes in the standalone public/supercoach-program-planner.html, which DECISIONS #10 proposes leaving out of the system. Inside the app, on/off controls are switches (.react-toggle, .toggle-switch), which map to Switch, not to this component.

Classes and selectors

  • .goal-toggle-btn7
  • .tgl5
  • .sub-toggle-btn4
  • .tgl.tgl-no3
  • .goal-toggle-btn:hover2
  • .tgl.tgl-yes2
  • .sub-toggle-btn:hover1
  • .tgl:hover1

Toggle group, Switch, Checkbox, Button.