Segmented Control

Switch between grouped views with one control, a segmented track or underline tabs, with icon-only segments and badge counts on each option.

import { SegmentedControl, SegmentedControlOption } from "@plexui/vue/components/SegmentedControl";

Examples

Overview

variant
placement
orientation
size
size
mobileMaterial
Standup07:00
Design review08:00
Focus time09:00
Lunch10:00
Interviews11:00
Planning12:00
Gym13:00
Dinner14:00
Standup15:00
Design review16:00
Focus time17:00
Lunch18:00
Interviews19:00
Planning20:00
Gym21:00
Dinner22:00

Segmented with icons

size

Icon only

variant
size

Segmented with badge

size

Underline

size

Underline flush

size

Underline block

size

Underline with icons

size

Underline with badge

size

Vertical segmented

size

Vertical underline

size

Vertical underline with icons

size

Sizing

variant
size

Scrollable

variant
size

Overflow menu

container width

SegmentedControl shares the unified 9-step size scale with Button, Input, Select, and SelectControl.

Also exported as Tabs

The same component is exported as Tabs, with TabsTab for an option, for code that names it so:

<script setup lang="ts">
import { ref } from "vue"
import { Tabs, TabsTab } from "@plexui/vue/components/Tabs"

const mode = ref("a")
</script>

<template>
  <Tabs v-model:value="mode" aria-label="Mode">
    <TabsTab value="a">A</TabsTab>
  </Tabs>
</template>

SegmentedControlOption, SegmentedControlTab, TabsOption and TabsTab are one component.

API

SegmentedControl (root)

PropTypeDefaultDescription
valuestring—Selected tab value. Bind with v-model:value; leave unset for an uncontrolled group
variant"segmented" | "underline""segmented"Visual style: segmented (background highlight) or underline (line indicator)
orientation"horizontal" | "vertical""horizontal"Layout direction of the tab group
size"3xs" | "2xs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl""md"Control height (3xs through 3xl). On a phone sm and smaller are the small 32px iOS control and md through 3xl the large 48px one (49px when flat); in a phone Toolbar it is the large one
gutter-size"2xs" | "xs" | "sm" | "md" | "lg" | "xl"—Horizontal padding of tabs
pillbooleantrueFully rounded control (segmented variant only)
flushbooleanfalseText-width indicator, no border, gap spacing (underline variant only)
blockbooleanfalseFull-width control with equal-width tabs
mobileMaterial"glass" | "flat""glass" at md and larger, "flat" at sm and smallerPhone surface of horizontal tabs, as for Button: flat makes the large control plain (49px), glass puts the small one under Liquid Glass
disabledbooleanfalseDisable all tabs
aria-labelstring—Accessible name (required)
overflow"scroll" | "menu""scroll"Options that do not fit: scroll sideways, or move into a menu at the end (horizontal, not block)
overflow-labelstring"More"Text of the menu button with overflow="menu"
classstring—Extra classes on the group element
default slotVNode[]—SegmentedControlOption children
@update:value(value: string) => void—Emitted when a tab is selected; powers v-model:value
@change(value: string) => void—Emitted with update:value, named after the React onChange prop
@click(event: MouseEvent) => void—Emitted on any click in the group, even when the selection does not change

SegmentedControlOption

PropTypeDefaultDescription
valuestring—Tab value (required)
disabledboolean—Disable this tab
iconComponent | VNode | string—Icon before the label (sized automatically); the icon slot takes precedence
badgenumber | string | VNode | { content; color?; variant?; pill?; loading? }—Badge/count or custom badge config
aria-labelstring—Accessible name (required for icon-only tabs)
default slotVNode[]—Tab label
icon slotVNode[]—Icon before the label
badge slotVNode[]—Badge content; styling still comes from the badge object

Styling

SegmentedControl reads these component tokens. Override them at any scope to restyle it:

  • --badge-font-size-2xs: font size 2xs (default var(--font-text-xs-size))
  • --badge-font-size-lg: font size lg (default var(--font-text-sm-size))
  • --badge-font-size-md: font size md (default var(--font-text-sm-size))
  • --badge-font-size-sm: font size sm (default var(--font-text-xs-size))
  • --badge-font-size-xs: font size xs (default var(--font-text-xs-size))
  • --badge-font-weight-2xs: font weight 2xs (default var(--font-weight-semibold))
  • --badge-font-weight-lg: font weight lg (default var(--font-weight-semibold))
  • --badge-font-weight-md: font weight md (default var(--font-weight-semibold))
  • --badge-font-weight-sm: font weight sm (default var(--font-weight-semibold))
  • --badge-font-weight-xs: font weight xs (default var(--font-weight-semibold))
  • --badge-gutter-2xs: gutter 2xs (default 0.1875rem)
  • --badge-gutter-lg: gutter lg (default var(--control-gutter-xs))
  • --badge-gutter-md: gutter md (default var(--control-gutter-2xs))
  • --badge-gutter-sm: gutter sm (default calc(var(--control-gutter-2xs) - 1px))
  • --badge-gutter-xs: gutter xs (default 0.25rem)
  • --badge-radius-2xs: radius 2xs (default var(--radius-2xs))
  • --badge-radius-lg: radius lg (default var(--radius-sm))
  • --badge-radius-md: radius md (default var(--radius-xs))
  • --badge-radius-sm: radius sm (default var(--radius-xs))
  • --badge-radius-xs: radius xs (default var(--radius-2xs))
  • --badge-size-2xs: size 2xs (default 1rem)
  • --badge-size-lg: size lg (default var(--control-size-2xs))
  • --badge-size-md: size md (default var(--control-size-3xs))
  • --badge-size-sm: size sm (default calc(var(--control-size-3xs) - 2px))
  • --badge-size-xs: size xs (default 1.125rem)
  • --badge-tracking-2xs: tracking 2xs (default var(--tracking-wide))
  • --badge-tracking-lg: tracking lg (default var(--tracking-normal))
  • --badge-tracking-md: tracking md (default var(--tracking-normal))
  • --badge-tracking-sm: tracking sm (default var(--tracking-wide))
  • --badge-tracking-xs: tracking xs (default var(--tracking-wide))
  • --button-gap-lg: gap lg (default 6px)
  • --button-gap-md: gap md (default 4px)
  • --button-gap-sm: gap sm (default 3px)
  • --segmented-control-background: background (default light-dark(var(--gray-100), var(--alpha-08)))
  • --segmented-control-font-weight: font weight (default var(--font-weight-semibold))
  • --segmented-control-gap: gap (default 2px)
  • --segmented-control-gutter: gutter (default 2px)
  • --segmented-control-mobile-plain-background: phone track in content, the tertiary fill (default light-dark(var(--alpha-06), var(--alpha-12)))
  • --segmented-control-mobile-plain-thumb-background: phone thumb in content (default light-dark(var(--gray-0), var(--alpha-25)))
  • --segmented-control-mobile-thumb-background: phone thumb background on the glass track in a Toolbar (default light-dark(var(--alpha-08), var(--gray-200)))
  • --segmented-control-symbol-size: phone icon of an icon-only segment (default 20px with touch.css, otherwise the icon size)
  • --segmented-control-option-highlight-background-color: option highlight background color (default light-dark( var(--gray-200), var(--gray-300) ))
  • --segmented-control-option-highlight-gutter: option highlight gutter (default 1px)
  • --segmented-control-sheen, --segmented-control-shadow, --segmented-control-backdrop-filter: the track's glass in a phone Toolbar, set by touch.css from the shared mobile glass (default none)
  • --segmented-control-thumb-background: thumb background (default light-dark(var(--gray-0), var(--alpha-12)))
  • --segmented-control-thumb-outset: how far the phone thumb reaches past its segment toward the capsule's ends (4px in a phone Toolbar with touch.css, default 0px)
  • --segmented-control-thumb-shadow: thumb shadow (default 0 1px 4px -1px rgb(0 0 0 / 20%))
  • --tabs-underline-border-color: underline border color (default var(--color-border))
  • --tabs-underline-indicator-color: underline indicator color (default var(--color-background-primary-solid))
  • --tabs-underline-indicator-height: underline indicator height (default 2px)