Segmented control

SvSegmented: mutually-exclusive options in a shared track (a view switcher, a range picker). Single-select, keyboard-accessible (arrow keys + Space/Enter via the radio-group core), with sizes, full-width, icons and disabled states. Themed from the --sg-* tokens.

A live, editable Svelte 5 component example from the SvGrid gallery (Buttons & Toggles). Read the SvGrid UI component docs for the full API.

About this example

SvSegmented, a segmented control for Svelte 5: mutually exclusive options in a shared track, used as a view switcher and a range picker. It is single-select and keyboard accessible with arrow keys and Space or Enter through the radio-group core, supports icons per option, disabled options and a full-width block layout, binds its value and is themed from the --sg-* tokens as the modern alternative to a small radio group.

SvSegmented - a segmented control: mutually-exclusive options in a shared track. Single-select, keyboard-accessible (arrow keys + Space/Enter), and themed from the --sg-* tokens. The modern alternative to a small radio group.

Imports, features and API used

Imports: @svgrid/grid

Frequently asked questions

How do I bind the selection?

Use bind:value with the options array of { value, label }. The selected segment slides into place and the bound value updates.

When should I use a segmented control over tabs?

For a small set of mutually exclusive choices that change a view or a parameter, such as Board and Table or Day and Week. Tabs suit larger content panels.

Can segments show icons?

Yes. Each option can carry an icon snippet with or without a label, and block mode stretches the segments across the container.

Related documentation

Related articles

Source code (408-segmented.svelte)

<script lang="ts">
  /**
   * SvSegmented - a segmented control: mutually-exclusive options in a shared
   * track. Single-select, keyboard-accessible (arrow keys + Space/Enter), and
   * themed from the --sg-* tokens. The modern alternative to a small radio group.
   */
  import { SvSegmented } from '@svgrid/grid'

  let view = $state('board')
  let range = $state('7d')
  let density = $state('comfortable')
  let align = $state('left')
</script>

<div class="wrap">
  <section>
    <h3>View switcher</h3>
    <SvSegmented
      label="View"
      bind:value={view}
      options={[{ value: 'board', label: 'Board' }, { value: 'table', label: 'Table' }, { value: 'calendar', label: 'Calendar' }]}
    />
    <p class="muted">Selected: <strong>{view}</strong></p>
  </section>

  <section>
    <h3>Sizes</h3>
    <div class="col">
      <SvSegmented size="sm" bind:value={range} options={[{ value: '24h', label: '24h' }, { value: '7d', label: '7d' }, { value: '30d', label: '30d' }]} />
      <SvSegmented size="md" bind:value={range} options={[{ value: '24h', label: '24h' }, { value: '7d', label: '7d' }, { value: '30d', label: '30d' }]} />
      <SvSegmented size="lg" bind:value={range} options={[{ value: '24h', label: '24h' }, { value: '7d', label: '7d' }, { value: '30d', label: '30d' }]} />
    </div>
  </section>

  <section>
    <h3>Full width + icons</h3>
    <SvSegmented block bind:value={align} options={[
      { value: 'left', label: 'Left', icon: iconLeft },
      { value: 'center', label: 'Center', icon: iconCenter },
      { value: 'right', label: 'Right', icon: iconRight },
    ]} />
  </section>

  <section>
    <h3>Disabled</h3>
    <SvSegmented disabled bind:value={density} options={[{ value: 'comfortable', label: 'Comfortable' }, { value: 'compact', label: 'Compact' }]} />
  </section>
</div>

{#snippet iconLeft()}<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 6h16M4 12h10M4 18h13" /></svg>{/snippet}
{#snippet iconCenter()}<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 6h16M7 12h10M6 18h12" /></svg>{/snippet}
{#snippet iconRight()}<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 6h16M10 12h10M7 18h13" /></svg>{/snippet}

<style>
  .wrap { padding: 22px; display: flex; flex-direction: column; gap: 24px; max-width: 460px; }
  section h3 { margin: 0 0 10px; font-size: 14px; font-weight: 700; }
  .col { display: flex; flex-direction: column; gap: 10px; align-items: flex-start; }
  .muted { margin: 8px 0 0; color: var(--sg-muted, #64748b); font-size: 13px; }
</style>

View this example on GitHub

More Buttons & Toggles examples

  • Buttons & toggles - The UI kit press/toggle primitives: SvButton (variants/sizes/loading), SvRepeatButton (hold-to-repeat), SvToggleButton, SvSwitchButton, SvCheckBox (+ indeterminate), SvRadioGroup (arrow-key nav) and SvRating (half stars). Theme-driven, standalone or as grid cell controls.
  • Button group - SvButtonGroup: a segmented button bar - single-select (radio semantics, a view switcher), multi-select (a toggle set / formatting toolbar) or plain actions. Roving tabindex + arrow keys, and the shared editor contract (label, validation, dir/RTL).
  • Button - SvButton in production: a toolbar (variants primary/secondary/outline/ghost/danger), sizes, icon slots, a loading state and a full-width CTA. Copy-paste-ready blocks.
  • Repeat button - SvRepeatButton: hold-to-repeat with acceleration - a quantity stepper and a volume control block.
  • Toggle button - SvToggleButton: a pressed on/off button (aria-pressed) - a text-formatting toolbar and pin / live state toggles.