<!-- https://svgrid.com/docs/help/ui-components/sv-segmented/ - SvGrid documentation as markdown. Index of every page: https://svgrid.com/llms.txt -->

# SvSegmented

A segmented control: a compact row of mutually-exclusive options in a shared
track - the modern alternative to a small radio group or a tab strip for a
setting.

`SvSegmented` renders single-select options as pill buttons in one track. It
reuses the radio-group core, so it is a proper `role="radiogroup"` with arrow-key
roaming and Space/Enter selection, and it themes from the shared `--sg-*` tokens.
Reach for it for view switchers, range pickers, and small enum settings.

Related: [SvRadioGroup](https://svgrid.com/docs/help/ui-components/sv-radio-group/) · [SvButtonGroup](https://svgrid.com/docs/help/ui-components/sv-button-group/) · [SvTabs](https://svgrid.com/docs/help/ui-components/sv-tabs/)

## Installation

Add it with the CLI - this drops a ready-to-edit `SvSegmented` starter into your app:

<div data-docs-add="add segmented"></div>

Prefer to see it first? `npx @svgrid/ui try segmented` opens it in a throwaway sandbox - no project needed.

Or install the package and import it directly. `SvSegmented` ships free in
`@svgrid/grid` (dependency-free):

<div data-docs-install="@svgrid/grid"></div>

The examples on this page import from `@svgrid/grid`:

```svelte
<script lang="ts">
  import { SvSegmented } from '@svgrid/grid'

  // The bound value behind each example below.
  let align = $state('')
  let period = $state('')
</script>
```

```ts
import { SvSegmented } from '@svgrid/grid'
```

## Example

> Live demo: Segmented control - https://svgrid.com/demos/408-segmented/

```svelte
<script lang="ts">
  import { SvSegmented } from '@svgrid/grid'
  let view = $state('board')
</script>

<SvSegmented
  bind:value={view}
  options={[
    { value: 'board', label: 'Board' },
    { value: 'table', label: 'Table' },
    { value: 'calendar', label: 'Calendar' },
  ]}
/>
```

## Props

| Prop        | Type                                   | Default | Description                                                    |
| ----------- | -------------------------------------- | ------- | ------------------------------------------------------------- |
| `options`   | `SegmentedOption[]`                    | -       | The choices: `{ value; label; disabled?; icon? }`.            |
| `value`     | `string \| number \| null`             | `null`  | Selected value (bindable).                                    |
| `onChange`  | `(value) => void`                      | -       | Fires when the selection changes.                             |
| `size`      | `sm` \| `md` \| `lg`                   | `md`    | Control height and font size.                                 |
| `block`     | `boolean`                              | `false` | Stretch full width and split options evenly.                  |
| `disabled`  | `boolean`                              | `false` | Disable the whole control.                                    |
| `label` / `hint` / `error` / `required` | -                  | -       | Optional [SvField](https://svgrid.com/docs/help/ui-components/sv-field/) chrome around the control.    |
| `dir`       | `EditorDir` (`ltr` \| `rtl` \| `auto`) | -       | Text direction.                                               |
| `name`      | `string`                               | -       | Emit a hidden input carrying the value for form posts.        |

`SegmentedOption` is `{ value; label; disabled?; icon?: Snippet }`.

## Examples

### Full width with icons

Set `block` to split the track evenly, and give options an `icon` snippet:

```svelte
<SvSegmented block bind:value={align} options={[
  { value: 'left', label: 'Left', icon: leftIcon },
  { value: 'center', label: 'Center', icon: centerIcon },
  { value: 'right', label: 'Right', icon: rightIcon },
]} />
```

### As a field

Pass `label` / `hint` / `error` to wrap it in the shared field chrome:

```svelte
<SvSegmented label="Billing period" bind:value={period} required
  error={period ? undefined : 'Pick a period'}
  options={[{ value: 'monthly', label: 'Monthly' }, { value: 'yearly', label: 'Yearly' }]} />
```

## Accessibility

- The control is a `role="radiogroup"` and each option a `role="radio"` with a
  single tab stop and roving `tabindex`.
- Keyboard: Left/Right (and Up/Down) move between options and select them; Space
  or Enter selects the focused option; disabled options are skipped.
- Give it a `label` (or `ariaLabel`) so the group is named for assistive tech.

## Sizes

Every control takes the same three sizes, so a dense toolbar and a roomy form can share components.

```svelte
<script lang="ts">
  import { SvSegmented } from '@svgrid/grid'

  let view = $state('')
</script>

<SvSegmented bind:value={view} size="sm" />
<SvSegmented bind:value={view} size="md" />
<SvSegmented bind:value={view} size="lg" />
```

## In a form

The shared field props behave the same on every editor: `label` names it, `hint` explains it, and `error` plus `invalid` mark it - which is why a validated form does not need per-component handling.

```svelte
<script lang="ts">
  import { SvSegmented } from '@svgrid/grid'

  let view = $state('')
</script>

<SvSegmented
  bind:value={view}
  label="Label"
  hint="A short hint"
  required
/>

<SvSegmented
  bind:value={view}
  label="Label"
  error="Something is wrong"
  invalid
/>
```

## See also

- [SvRadioGroup](https://svgrid.com/docs/help/ui-components/sv-radio-group/) - the classic radio list on the same core.
- [SvTabs](https://svgrid.com/docs/help/ui-components/sv-tabs/) - when each option reveals a whole panel of content.
- [SvButtonGroup](https://svgrid.com/docs/help/ui-components/sv-button-group/) - a segmented cluster of action buttons.

---

SvGrid is the Svelte 5 data grid (`npm install @svgrid/grid`, MIT). This page: https://svgrid.com/docs/help/ui-components/sv-segmented/ . All docs: https://svgrid.com/llms.txt
