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
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)
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | 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 |
pill | boolean | true | Fully rounded control (segmented variant only) |
flush | boolean | false | Text-width indicator, no border, gap spacing (underline variant only) |
block | boolean | false | Full-width control with equal-width tabs |
mobileMaterial | "glass" | "flat" | "glass" at md and larger, "flat" at sm and smaller | Phone surface of horizontal tabs, as for Button: flat makes the large control plain (49px), glass puts the small one under Liquid Glass |
disabled | boolean | false | Disable all tabs |
aria-label | string | — | 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-label | string | "More" | Text of the menu button with overflow="menu" |
class | string | — | Extra classes on the group element |
default slot | VNode[] | — | 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
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Tab value (required) |
disabled | boolean | — | Disable this tab |
icon | Component | VNode | string | — | Icon before the label (sized automatically); the icon slot takes precedence |
badge | number | string | VNode | { content; color?; variant?; pill?; loading? } | — | Badge/count or custom badge config |
aria-label | string | — | Accessible name (required for icon-only tabs) |
default slot | VNode[] | — | Tab label |
icon slot | VNode[] | — | Icon before the label |
badge slot | VNode[] | — | 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 (defaultvar(--font-text-xs-size))--badge-font-size-lg: font size lg (defaultvar(--font-text-sm-size))--badge-font-size-md: font size md (defaultvar(--font-text-sm-size))--badge-font-size-sm: font size sm (defaultvar(--font-text-xs-size))--badge-font-size-xs: font size xs (defaultvar(--font-text-xs-size))--badge-font-weight-2xs: font weight 2xs (defaultvar(--font-weight-semibold))--badge-font-weight-lg: font weight lg (defaultvar(--font-weight-semibold))--badge-font-weight-md: font weight md (defaultvar(--font-weight-semibold))--badge-font-weight-sm: font weight sm (defaultvar(--font-weight-semibold))--badge-font-weight-xs: font weight xs (defaultvar(--font-weight-semibold))--badge-gutter-2xs: gutter 2xs (default0.1875rem)--badge-gutter-lg: gutter lg (defaultvar(--control-gutter-xs))--badge-gutter-md: gutter md (defaultvar(--control-gutter-2xs))--badge-gutter-sm: gutter sm (defaultcalc(var(--control-gutter-2xs) - 1px))--badge-gutter-xs: gutter xs (default0.25rem)--badge-radius-2xs: radius 2xs (defaultvar(--radius-2xs))--badge-radius-lg: radius lg (defaultvar(--radius-sm))--badge-radius-md: radius md (defaultvar(--radius-xs))--badge-radius-sm: radius sm (defaultvar(--radius-xs))--badge-radius-xs: radius xs (defaultvar(--radius-2xs))--badge-size-2xs: size 2xs (default1rem)--badge-size-lg: size lg (defaultvar(--control-size-2xs))--badge-size-md: size md (defaultvar(--control-size-3xs))--badge-size-sm: size sm (defaultcalc(var(--control-size-3xs) - 2px))--badge-size-xs: size xs (default1.125rem)--badge-tracking-2xs: tracking 2xs (defaultvar(--tracking-wide))--badge-tracking-lg: tracking lg (defaultvar(--tracking-normal))--badge-tracking-md: tracking md (defaultvar(--tracking-normal))--badge-tracking-sm: tracking sm (defaultvar(--tracking-wide))--badge-tracking-xs: tracking xs (defaultvar(--tracking-wide))--button-gap-lg: gap lg (default6px)--button-gap-md: gap md (default4px)--button-gap-sm: gap sm (default3px)--segmented-control-background: background (defaultlight-dark(var(--gray-100), var(--alpha-08)))--segmented-control-font-weight: font weight (defaultvar(--font-weight-semibold))--segmented-control-gap: gap (default2px)--segmented-control-gutter: gutter (default2px)--segmented-control-mobile-plain-background: phone track in content, the tertiary fill (defaultlight-dark(var(--alpha-06), var(--alpha-12)))--segmented-control-mobile-plain-thumb-background: phone thumb in content (defaultlight-dark(var(--gray-0), var(--alpha-25)))--segmented-control-mobile-thumb-background: phone thumb background on the glass track in a Toolbar (defaultlight-dark(var(--alpha-08), var(--gray-200)))--segmented-control-symbol-size: phone icon of an icon-only segment (default20pxwithtouch.css, otherwise the icon size)--segmented-control-option-highlight-background-color: option highlight background color (defaultlight-dark( var(--gray-200), var(--gray-300) ))--segmented-control-option-highlight-gutter: option highlight gutter (default1px)--segmented-control-sheen,--segmented-control-shadow,--segmented-control-backdrop-filter: the track's glass in a phone Toolbar, set bytouch.cssfrom the shared mobile glass (defaultnone)--segmented-control-thumb-background: thumb background (defaultlight-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 (4pxin a phone Toolbar withtouch.css, default0px)--segmented-control-thumb-shadow: thumb shadow (default0 1px 4px -1px rgb(0 0 0 / 20%))--tabs-underline-border-color: underline border color (defaultvar(--color-border))--tabs-underline-indicator-color: underline indicator color (defaultvar(--color-background-primary-solid))--tabs-underline-indicator-height: underline indicator height (default2px)