Skip to content

SegmentedControl

Mutually-exclusive choice rendered as a horizontal group of buttons. Use for view-mode toggles, density selectors, time-range pickers — anywhere a small fixed set of options needs to surface inline. For binary on/off, use a Toggle. For longer / searchable lists, use Combobox or Listbox.

Basic

html
<SegmentedControl v-model="value" :options="options" />
ts
const options = [
    { label: 'List', value: 'list' },
    { label: 'Grid', value: 'grid' },
    { label: 'Map', value: 'map' },
]

Sizes

html
<SegmentedControl v-model="value" :options="options" size="sm" />
<SegmentedControl v-model="value" :options="options" size="md" />

Variants

The variant changes the active-segment color treatment.

html
<SegmentedControl v-model="value" :options="options" variant="primary" />
<SegmentedControl v-model="value" :options="options" variant="secondary" />
<SegmentedControl v-model="value" :options="options" variant="tertiary" />

Disabled options

Mark individual options as disabled to render them inert. The user can still see them — they just can't be selected.

html
<SegmentedControl v-model="range" :options="rangeOptions" />
ts
const rangeOptions = [
    { label: 'Day', value: 'day' },
    { label: 'Week', value: 'week' },
    { label: 'Month', value: 'month' },
    { label: 'Custom', value: 'custom', disabled: true },
]

Custom option content

Use the option slot to render anything inside each segment — icons + labels, badges, etc. The slot receives the full option object.

html
<SegmentedControl v-model="value" :options="options">
  <template #option="{ option }">
    <span class="inline-flex items-center gap-1.5">
      <Icon :name="option.icon" :size="16" />
      {{ option.label }}
    </span>
  </template>
</SegmentedControl>

Props

PropTypeDefaultDescription
modelValuestring | numberrequiredSelected value. Use v-model.
options{ label: string; value: string | number; disabled?: boolean }[]requiredSegment options.
size'sm' | 'md''md'Segment height + typography.
variant'primary' | 'secondary' | 'tertiary''primary'Active-segment color treatment.

Slots

SlotSlot propsDescription
option{ option }Override the default label rendering for every segment.

Events

EventDescription
update:modelValueEmitted when the user selects a different option.

Accessibility

The wrapper has role="group" with aria-label="Segmented control". Each segment is a real <button> with aria-pressed reflecting the selected state, and disabled honored.