Tabs
A neo-brutalist style tab navigation component built on top of reka-ui's Tabs primitive. Supports horizontal/vertical layouts, controlled mode, and multiple active state color variants.
Demo
水平布局(默认)
在此修改您的账户信息。完成后请点击保存。
垂直布局
通用设置选项,包括语言、主题等基础配置。
数据驱动模式(tabs prop)
概览
Installation
pnpm dlx brutx-vue@latest add tabsUsage
<script setup>
import { Tabs, TabsList, TabsTrigger, TabsContent } from 'brutx-ui-vue/tabs'
</script>
<template>
<Tabs default-value="account">
<TabsList>
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="password">Password</TabsTrigger>
</TabsList>
<TabsContent value="account">
<p class="text-sm">Manage your account settings.</p>
</TabsContent>
<TabsContent value="password">
<p class="text-sm">Change your password here.</p>
</TabsContent>
</Tabs>
</template>Vertical Layout
Set the orientation prop on Tabs to vertical for a vertical layout. In vertical mode, TabsList automatically switches to a vertical arrangement (flex-col), making it suitable for sidebar navigation and similar scenarios.
The orientation prop is passed to child components via dependency injection, so TabsList automatically adapts to the direction without needing to be set individually. If you need to override the direction on a single TabsList, you can set its orientation prop directly.
<script setup>
import { Tabs, TabsList, TabsTrigger, TabsContent } from 'brutx-ui-vue/tabs'
</script>
<template>
<Tabs default-value="general" orientation="vertical" class="flex gap-4">
<TabsList>
<TabsTrigger value="general">General</TabsTrigger>
<TabsTrigger value="security">Security</TabsTrigger>
<TabsTrigger value="notifications">Notifications</TabsTrigger>
</TabsList>
<TabsContent value="general">
<p class="text-sm">General settings options.</p>
</TabsContent>
<TabsContent value="security">
<p class="text-sm">Security settings options.</p>
</TabsContent>
<TabsContent value="notifications">
<p class="text-sm">Notification settings options.</p>
</TabsContent>
</Tabs>
</template>Controlled Mode
Use v-model for controlled tab switching:
<script setup>
import { ref } from 'vue'
import { Tabs, TabsList, TabsTrigger, TabsContent } from 'brutx-ui-vue/tabs'
const currentTab = ref('account')
</script>
<template>
<Tabs v-model="currentTab">
<TabsList>
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="password">Password</TabsTrigger>
</TabsList>
<TabsContent value="account">
<p class="text-sm">Manage your account settings.</p>
</TabsContent>
<TabsContent value="password">
<p class="text-sm">Change your password here.</p>
</TabsContent>
</Tabs>
</template>Data-driven Mode (tabs Prop)
Pass a tabs array to render TabsList, TabsTrigger, and default TabsContent panels automatically. Omit tabs to compose the complete structure through the default slot.
<script setup lang="ts">
import { Tabs } from 'brutx-ui-vue/tabs'
import type { TabItem } from 'brutx-ui-vue/tabs'
const tabs: TabItem[] = [
{ label: 'Overview', value: 'overview' },
{ label: 'Analytics', value: 'analytics' },
{ label: 'Settings', value: 'settings' },
]
</script>
<template>
<Tabs :tabs="tabs" default-value="overview" />
</template>Custom Content Panels
The default slot replaces the generated Card panels while TabsList continues to be generated from tabs:
<script setup lang="ts">
import { Tabs, TabsContent } from 'brutx-ui-vue/tabs'
import type { TabItem } from 'brutx-ui-vue/tabs'
const tabs: TabItem[] = [
{ label: 'Tab A', value: 'a' },
{ label: 'Tab B', value: 'b' },
]
</script>
<template>
<Tabs :tabs="tabs">
<template #default>
<TabsContent value="a">
<p class="text-sm">Custom content for A</p>
</TabsContent>
<TabsContent value="b">
<p class="text-sm">Custom content for B</p>
</TabsContent>
</template>
</Tabs>
</template>header / footer Slots
In data-driven mode, the header and footer slots add content above and below the tab region. An empty tabs array displays a localized Result empty state while retaining these slots.
Controlled and Uncontrolled State
- Providing
modelValueor usingv-modelmakes the parent control the active value. - Omitting
modelValuelets the component maintain its active value internally. - The initial selection uses
defaultValue, then the first item value. If the selected item is removed, the same fallback order applies.
Variants
TabsTrigger supports the following active state color variants:
| Variant | Description |
|---|---|
default | Default active state style |
primary | Primary (coral) background |
secondary | Secondary background |
success | Success (green) background |
<template>
<TabsTrigger value="tab" variant="primary">Primary variant</TabsTrigger>
</template>Sizes
TabsList supports the following container sizes:
| Size | Description |
|---|---|
sm | Small |
default | Default |
lg | Large |
Sub-components
| Component | Description |
|---|---|
Tabs | Root component (wraps reka-ui's TabsRoot) |
TabsList | Tab trigger container |
TabsTrigger | Clickable tab button |
TabsContent | Content panel for each tab |
Exported Types
Import from the brutx-ui-vue/tabs sub-path:
import {
Tabs,
TabsList,
TabsTrigger,
TabsContent,
tabsListVariants,
tabsTriggerVariants,
tabsContentVariants,
} from 'brutx-ui-vue/tabs'
import type { TabItem } from 'brutx-ui-vue/tabs'
import { TabsRoot } from 'reka-ui'TabItem
The data item accepted by the tabs prop:
interface TabItem {
label: string
value: string
disabled?: boolean
}| Field | Type | Description |
|---|---|---|
label | string | Visible tab label |
value | string | Unique tab identifier |
disabled | boolean | Whether this tab is disabled (optional) |
Composables
The component exports the following variant utility functions for custom style extensions:
import {
tabsListVariants,
tabsTriggerVariants,
tabsContentVariants,
} from 'brutx-ui-vue/tabs'| Function | Variant Parameters | Description |
|---|---|---|
tabsListVariants | size: 'sm' | 'default' | 'lg', orientation: 'horizontal' | 'vertical' | Container style variants |
tabsTriggerVariants | variant: 'default' | 'primary' | 'secondary' | 'success' | Trigger style variants |
tabsContentVariants | — | Content panel base style |
API Reference
Tabs
| Name | Type | Default | Description |
|---|---|---|---|
modelValue | string | undefined | undefined | The active tab value in controlled mode, supporting v-model. When undefined, the component maintains selection internally. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/tabs/Tabs.vue | |||
defaultValue | string | undefined | undefinedRuntime fallback: | The initial uncontrolled tab value, also used as a fallback when the current selection disappears from the data list. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/tabs/Tabs.vue | |||
tabs | TabItem[] | undefined | undefined | The tab data list. A non-empty list renders triggers and default panels, an empty list shows a localized empty state, and omission enables composition through the default slot. |
DetailsDeclared typeTabItem[] | undefined Referenced types TabItem Type definition — TabItemexport interface TabItem {
label: string
value: string
disabled?: boolean
}Default value details
Sourcepackages/ui/src/components/tabs/Tabs.vue | |||
orientation | "vertical" | "horizontal" | undefined | "horizontal" | The root tab orientation for layout state and keyboard navigation, also providing the default orientation for TabsList. |
DetailsDeclared type"vertical" | "horizontal" | undefined Literal values
Default value details
Sourcepackages/ui/src/components/tabs/Tabs.vue | |||
class | string | undefined | undefined | Custom CSS classes applied to the outer container when tabs is provided, or to TabsRoot in composition mode. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/tabs/Tabs.vue | |||
| Name | Signature or type | Description |
|---|---|---|
@update:modelValue | [value: string] | Emits the new string value when the active tab changes, also updating internal selection in uncontrolled mode. |
DetailsDeclared type[value: string] Sourcepackages/ui/src/components/tabs/Tabs.vue | ||
| Name | Signature or type | Description |
|---|---|---|
#header | {} | Content above the tabs in data-driven mode, also rendered when tabs is an empty array. |
DetailsDeclared type{}Sourcepackages/ui/src/components/tabs/Tabs.vue | ||
#default | {} | Contains the complete tab structure in composition mode. In data-driven mode, replaces the generated panels and should supply TabsContent components. It is not rendered for an empty tabs array. |
DetailsDeclared type{}Sourcepackages/ui/src/components/tabs/Tabs.vue | ||
#footer | {} | Content below the tabs in data-driven mode, also rendered when tabs is an empty array. |
TabsContent
| Name | Type | Default | Description |
|---|---|---|---|
valueRequired | string | — | The tab value associated with this panel, matching its TabsTrigger value. |
DetailsDeclared typestring Default value details
Sourcepackages/ui/src/components/tabs/TabsContent.vue | |||
surface | TabsContentSurface | undefined | "plain" | Surface shell mode: plain for zero-padding fitting (ideal for nested Card), panel for standalone card shell with borders and shadow. |
DetailsDeclared typeTabsContentSurface | undefined Literal values
Referenced types TabsContentSurface Type definition — TabsContentSurfaceexport type TabsContentSurface = NonNullable<TabsContentVariantProps['surface']> Default value details
Sourcepackages/ui/src/components/tabs/TabsContent.vue | |||
forceMount | boolean | undefined | undefined | Keeps the panel mounted for external animation control or to retain the panel instance. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/tabs/TabsContent.vue | |||
class | string | undefined | undefined | Custom CSS classes merged onto the tab panel. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/tabs/TabsContent.vue | |||
| Name | Signature or type | Description |
|---|---|---|
#default | {} | The content associated with this tab. |
DetailsDeclared type{}Sourcepackages/ui/src/components/tabs/TabsContent.vue | ||
TabsList
| Name | Type | Default | Description |
|---|---|---|---|
size | "default" | "lg" | "sm" | undefined | "default" | The size variant of the tab list container. |
DetailsDeclared typeNonNullable<"default" | "lg" | "sm" | null | undefined> | undefined Literal values
Default value details
Sourcepackages/ui/src/components/tabs/TabsList.vue | |||
orientation | "horizontal" | "vertical" | undefined | undefinedRuntime fallback: | Overrides the list layout styles and data-orientation without changing the root Tabs keyboard orientation. |
DetailsDeclared typeNonNullable<"vertical" | "horizontal" | null | undefined> | undefined Literal values
Default value details
Sourcepackages/ui/src/components/tabs/TabsList.vue | |||
class | string | undefined | undefined | Custom CSS classes merged onto the tab list container. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/tabs/TabsList.vue | |||
| Name | Signature or type | Description |
|---|---|---|
#default | {} | The tab trigger list, typically containing TabsTrigger components. |
DetailsDeclared type{}Sourcepackages/ui/src/components/tabs/TabsList.vue | ||
TabsTrigger
| Name | Type | Default | Description |
|---|---|---|---|
valueRequired | string | — | The unique string identifier linking this tab to its TabsContent. |
DetailsDeclared typestring Default value details
Sourcepackages/ui/src/components/tabs/TabsTrigger.vue | |||
disabled | boolean | undefined | false | Disables this tab trigger and prevents user activation. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/tabs/TabsTrigger.vue | |||
variant | "accent" | "default" | "primary" | "secondary" | "slots" | "success" | undefined | "default" | The trigger visual variant, controlling active-state colors and decoration. |
DetailsDeclared typeNonNullable<"default" | "primary" | "secondary" | "success" | "accent" | "slots" | null | undefined> | undefined Literal values
Default value details
Sourcepackages/ui/src/components/tabs/TabsTrigger.vue | |||
class | string | undefined | undefined | Custom CSS classes merged onto the tab trigger. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/tabs/TabsTrigger.vue | |||
| Name | Signature or type | Description |
|---|---|---|
#default | {} | Text, icons, or other label content inside the tab trigger. |
DetailsDeclared type{}Sourcepackages/ui/src/components/tabs/TabsTrigger.vue | ||
Accessibility
- Keyboard: Arrow keys navigate between tab triggers
- ARIA Attributes: Tab content is associated with its trigger via ARIA attributes; the active tab has
aria-selected="true"