Components › Forms & input › Choice › Segmented control

Segmented control

canon

Inline group of mutually exclusive buttons for switching modes.

acrm !4066 (28 Sep 2026): SegmentedOption.count?: number — neutral .acrm-count after the label (CountBadge look, never accent), 0 not drawn; first use segment detail "Vše | Přírůstky (N)" (replaced .sgb-ctl chips). 30 Sep 2026 (acrm !4252, AD FA218): option prop tone?: positive | warning | critical colours only the TEXT of the selected option (.on.seg-tone-*) with --positive-ink / --warning-ink / --critical-ink (AA ≥ 5.3:1 light and dark). Only for an answer with meaning (yes / maybe / no, e.g. meeting RSVP), never decoration; selection still carried by the surface and aria-pressed.

Used in 58 files · 35 areas · 71× — components/accounting, components/agent-desk, components/assistant, components/callwrapup, components/clen-tymu, components/costs …

Inline group of mutually exclusive buttons for switching modes. React <Segmented> (packages/ui/src/components/Segmented.tsx) emits .acrm-segmented > button(.on)[aria-pressed] from apps/web/src/ds.css; the builder engine .sgb-seg is a separate DS port and stays its own.

When to use

  • One choice out of 2–5 short labels: "All" / "Several branches" / "Headquarters only", "Yes" / "No".
  • View switch in a Section top bar next to the title (Calendar "Month" / "Week"; Tasks, Hovory, Journal, Naklady).
  • Form switch in a drawer or dialog — grow for full width and even columns ("User" / "Team" owner).
  • Options with a meaningful icon — pass icon on the option (--ico-xs before the label).

When not to use

  • Options that need more than a couple of words or a description — use Radio.
  • More than ~5 options or a list that grows — use Select.
  • Navigation between pages or record tabs — use Tabs / Record tabs, not a segmented control.
  • Independent multi-toggles (several may be on) — use Option chips.
  • A bespoke button group built from .acrm-btn — the registry lists .acrm-btn under this sub, but Segmented.tsx does not emit it; drop it from classes.

Anatomy

  • Track: .acrm-segmented — inline-flex, gap: var(--sp-0), padding: var(--sp-0) (2px), background: var(--line-100), border-radius: var(--radius-sm); total height 30px (2px gutter + 26px segment — card Inputs).
  • Segment: > button 26px, padding: 0 var(--sp-3), no border, border-radius: var(--radius-xs), font var(--small), color var(--fg-secondary), transparent.
  • Selected: .on (or [aria-selected='true']) = background: var(--surface-100), color var(--fg), box-shadow: var(--shadow-xs); aria-pressed="true" on the same button.
  • Icon: .ti at var(--ico-xs) (14px) before the label, colour inherited from the segment.
  • grow: track becomes grid-auto-flow: column with 1fr columns; buttons inline-flex centred with gap: var(--sp-2).
  • Props: options[{key,label,icon?}], value, onChange(key), grow?, ariaLabel? — no size or disabled prop.
  • Frame rule: the selected segment is a raised white surface on the grey track — no accent fill, no accent border.

Count on an option (acrm !4066, 28 Sep 2026)

SegmentedOption.count?: number draws a neutral .acrm-count after the label (the same element as the app's CountBadge, never accent). 0 and undefined are not drawn. Readable on both the active (surface) and inactive (line) background — story Segmented control › Variants. First use: segment detail "Vše | Přírůstky (N)", which replaced two bespoke .sgb-ctl chips (a fixed 2–4 option set is Segmented, not .tchip).

Tone of the selected option (acrm !4252, 30 Sep 2026)

SegmentedOption.tone?: 'positive' | 'warning' | 'critical' colours only the label (and icon) of the SELECTED option with --positive-ink / --warning-ink / --critical-ink. Surface, shadow and unselected options stay as they are. Use it only for an answer that carries meaning — agree / unsure / decline, e.g. the meeting invitation reply "Ano · Možná · Ne" — never to decorate a view switch. Selection is still shown by the raised surface and aria-pressed; the colour only adds to it. Story Segmented control › with tone.

Best practices

Do
  • Always pass ariaLabel naming the choice ("View", "Owner", "Scope").
  • Keep labels one or two words and of similar length so segments look even.
  • Use grow only inside a field or drawer where the control spans the form width; the toolbar form stays compact.
  • Put the control next to the title in a Section top bar; the primary action stays on the right.
Don’t
  • More than 5 segments or wrapping labels — switch to Select or Radio.
  • Segmented as page navigation or as record tabs.
  • A copy with its own colours (.seg, Seg from .acrm-btn) — those were replaced by <Segmented>.
  • Accent fill on the selected segment.

Content

  • Labels in sentence case, nouns or short adjectives: "Month", "Week", "All", "Headquarters only".
  • No punctuation, no counts inside the label (a count belongs in a badge outside the control).
  • Order from the broadest to the narrowest option, or in the natural sequence (Day · Week · Month).
  • radio — the same exclusive choice with longer labels.
  • tab-strip — navigation between sections of a record.
  • option-chips — multi-toggle chips.
  • Stories: components--segmented-control--default, components--segmented-control--variants, components--segmented-control--with-icon-kbd, components--segmented-control--composition; legacy overview components--segmented-app-only-.

Source: docs/choice/segmented-control.usage.md · GitLab