Tabs
Switch between grouped views with segmented or underline tabs, icon-only triggers, and badge counts on each tab.
import { Tabs, TabsTab } from "@plexui/vue/components/Tabs";Examples
Overview
variant
orientation
size
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
Disabled tab
variant
size
Sizing
variant
size
Scrollable
variant
size
Overflow menu
width
Tabs shares the unified 9-step size scale with Button, Input, Select, and SelectControl.
Migration from SegmentedControl
Tabs replaces and extends SegmentedControl. As in the React package, the old import still works as an alias:
<script setup lang="ts">
import { ref } from "vue"
// Old (still works)
import { SegmentedControl, SegmentedControlOption } from "@plexui/vue/components/SegmentedControl"
// New (recommended)
import { Tabs, TabsTab } from "@plexui/vue/components/Tabs"
const mode = ref("a")
</script>
<template>
<SegmentedControl v-model:value="mode" aria-label="Mode">
<SegmentedControlOption value="a">A</SegmentedControlOption>
</SegmentedControl>
<Tabs v-model:value="mode" aria-label="Mode">
<TabsTab value="a">A</TabsTab>
</Tabs>
</template>TabsTab and TabsOption are the same component, and so are SegmentedControlOption and SegmentedControlTab. The SegmentedControl alias defaults to variant="segmented".
API
Tabs (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) |
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 |
disabled | boolean | false | Disable all tabs |
aria-label | string | — | Accessible name (required) |
overflow | "scroll" | "menu" | "scroll" | Tabs 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[] | — | TabsTab 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 |
TabsTab
| 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
Tabs 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(--gray-0)))--segmented-control-font-weight: font weight (defaultvar(--font-weight-semibold))--segmented-control-gap: gap (default2px)--segmented-control-gutter: gutter (default2px)--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-thumb-background: thumb background (defaultlight-dark(var(--gray-0), var(--gray-300)))--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)