| name | n-tabs |
| description | Tabs component for switching content in same area. Invoke when user needs to implement tabbed interfaces, content switching, or tab navigation in Naive UI. |
| metadata | {"author":"jiaiyan","version":"1.0.0"} |
Naive UI Tabs Component
Switch contents in same area. Organize content into separate tabbed panels.
When to Use
Use this component when:
- Content organization: Group related content into tabs
- Form sections: Separate form fields into logical groups
- Settings panels: Organize settings into categories
- Dashboard views: Switch between different data views
When to Invoke
Invoke this skill when:
- User needs to implement tabbed interfaces
- User wants to switch between content panels
- User needs addable or closable tabs
- User wants to customize tab appearance
- User asks about tab navigation or switching
Features
- Multiple Types: Bar, line, card, and segment types
- Addable/Closable: Add and remove tabs dynamically
- Animated Transitions: Smooth tab switching animations
- Placement Options: Top, bottom, left, right placement
- Trigger Modes: Click or hover to activate
- Before Leave Hook: Intercept tab switching
- Display Directives: Control content rendering behavior
API Reference
Tabs Props
| Name | Type | Default | Description | Version |
|---|
| addable | boolean | object | false | Whether to allow adding tabs (card type only). | |
| add-tab-class | string | undefined | Class of the add tab. | 2.37.0 |
| add-tab-style | string | object | undefined | Style of the add tab. | 2.37.0 |
| animated | boolean | false | Whether to enable animation. | 2.27.0 |
| bar-width | number | undefined | Width of the tab bar. | 2.25.0 |
| closable | boolean | false | Whether to allow closing tabs (card type only). | |
| default-value | string | number | undefined | Default value in uncontrolled mode. | |
| justify-content | string | undefined | Flex justify-content value. | 2.29.1 |
| size | 'small' | 'medium' | 'large' | 'medium' | Size of tabs. | |
| pane-class | string | undefined | Class of the pane. | |
| pane-style | string | object | undefined | Style of the pane. | |
| pane-wrapper-class | string | undefined | Class of the pane wrapper. | 2.34.4 |
| pane-wrapper-style | string | object | undefined | Style of the pane wrapper. |
TabPane Props
| Name | Type | Default | Description | Version |
|---|
| closable | boolean | false | Whether to allow closing (card type only). | |
| disabled | boolean | false | Whether to disable the tab. | |
| display-directive | 'if' | 'show' | 'show:lazy' | 'if' | Conditional rendering directive. | |
| name | string | number | undefined | Required, the name of the tab. | |
| tab | string | VNode | (() => VNodeChild) | undefined | Tab label. | |
| tab-props | Object | undefined | DOM attributes of tab label. | 2.24.2 |
Tab Props
| Name | Type | Default | Description |
|---|
| closable | boolean | false | Whether to allow closing (card type only). |
| disabled | boolean | false | Whether to disable. |
| name | string | number | undefined | Required, the name of the tab. |
Tabs Slots
| Name | Parameters | Description |
|---|
| default | () | Tabs content. |
| prefix | () | Tabs prefix. |
| suffix | () | Tabs suffix. |
TabPane Slots
| Name | Parameters | Description |
|---|
| default | () | Tab pane content. |
| tab | () | Tab label content. |
Tabs Methods
| Name | Type | Description | Version |
|---|
| syncBarPosition | () => void | Sync tab bar's position. | 2.24.0 |
Basic Usage
Basic Tabs
<template>
<n-tabs type="line" animated>
<n-tab-pane name="oasis" tab="Oasis">
Wonderwall
</n-tab-pane>
<n-tab-pane name="the beatles" tab="the Beatles">
Hey Jude
</n-tab-pane>
<n-tab-pane name="jay chou" tab="Jay Chou">
Qilixiang
</n-tab-pane>
</n-tabs>
</template>
Segment Type
<template>
<n-tabs type="segment" animated>
<n-tab-pane name="oasis" tab="Oasis">
Wonderwall
</n-tab-pane>
<n-tab-pane name="the beatles" tab="the Beatles">
Hey Jude
</n-tab-pane>
<n-tab-pane name="jay chou" tab="Jay Chou">
Qilixiang
</n-tab-pane>
</n-tabs>
</template>
Card Type with Closable
<template>
<n-tabs
v-model:value="name"
type="card"
closable
tab-style="min-width: 80px;"
@close="handleClose"
>
<n-tab-pane
v-for="panel in panels"
:key="panel"
:tab="panel.toString()"
:name="panel"
>
{{ panel }}
</n-tab-pane>
</n-tabs>
</template>
<script setup>
import { ref } from 'vue'
const name = ref(1)
const panels = ref([1, 2, 3, 4])
const handleClose = (name) => {
const index = panels.value.indexOf(name)
if (index > -1) {
panels.value.splice(index, 1)
}
}
</script>
Common Patterns
Addable Tabs
<template>
<n-tabs
v-model:value="value"
type="card"
:addable="addable"
:closable="closable"
tab-style="min-width: 80px;"
@close="handleClose"
@add="handleAdd"
>
<n-tab-pane v-for="panel in panels" :key="panel" :name="panel">
{{ panel }}
</n-tab-pane>
</n-tabs>
</template>
<script setup>
import { ref } from 'vue'
const value = ref(1)
const panels = ref([1, 2, 3])
const addable = ref(true)
const closable = ref(true)
const handleAdd = () => {
const newPanel = Math.max(...panels.value) + 1
panels.value.push(newPanel)
value.value = newPanel
}
const handleClose = (name) => {
const index = panels.value.indexOf(name)
if (index > -1) {
panels.value.splice(index, 1)
}
}
</script>
Before Leave Hook
<template>
<n-tabs
type="line"
default-value="okay"
@before-leave="handleBeforeLeave"
@update:value="handleUpdateValue"
>
<n-tab-pane name="wait" tab="Wait for 1s">
+1s
</n-tab-pane>
<n-tab-pane name="not-allowed" tab="Not allowed">
???
</n-tab-pane>
<n-tab-pane name="okay" tab="Okay">
Just so so
</n-tab-pane>
</n-tabs>
</template>
<script setup>
const handleBeforeLeave = async (activeName, oldActiveName) => {
if (activeName === 'not-allowed') {
return false
}
if (activeName === 'wait') {
await new Promise(resolve => setTimeout(resolve, 1000))
}
return true
}
const handleUpdateValue = (value) => {
console.log('Tab changed to:', value)
}
</script>
Prefix and Suffix
<template>
<n-tabs default-value="oasis">
<template #prefix>
Prefix
</template>
<n-tab-pane name="oasis" tab="Oasis">
Wonderwall
</n-tab-pane>
<n-tab-pane name="the beatles" tab="the Beatles">
Hey Jude
</n-tab-pane>
<template #suffix>
Suffix
</template>
</n-tabs>
</template>
Tabs Without Pane
<template>
<n-tabs type="line">
<n-tab name="Riders On the Storm">
Riders On the Storm
</n-tab>
<n-tab name="Light My Fire">
Light My Fire
</n-tab>
<n-tab name="Break On Through">
Break On Through
</n-tab>
</n-tabs>
</template>
Placement Options
<template>
<n-tabs
:type="type"
animated
:placement="placement"
:style="placement === 'left' || placement === 'right' ? { height: '240px' } : undefined"
>
<n-tab-pane name="oasis" tab="Oasis">
Wonderwall
</n-tab-pane>
<n-tab-pane name="the beatles" tab="the Beatles">
Hey Jude
</n-tab-pane>
<n-tab-pane name="jay chou" tab="Jay Chou">
Qilixiang
</n-tab-pane>
</n-tabs>
</template>
<script setup>
import { ref } from 'vue'
const type = ref('line')
const placement = ref('top')
</script>
Display Directive
<template>
<n-tabs default-value="show">
<n-tab-pane name="show" display-directive="show" tab="show">
Content preserved when switching
</n-tab-pane>
<n-tab-pane name="if" display-directive="if" tab="if">
Content reset when switching
</n-tab-pane>
<n-tab-pane name="show:lazy" display-directive="show:lazy" tab="show:lazy">
Lazy loaded and preserved
</n-tab-pane>
</n-tabs>
</template>
Hover Trigger
<template>
<n-tabs type="line" trigger="hover">
<n-tab-pane name="oasis" tab="Oasis">
Wonderwall
</n-tab-pane>
<n-tab-pane name="the beatles" tab="the Beatles">
Hey Jude
</n-tab-pane>
<n-tab-pane name="jay chou" tab="Jay Chou">
Qilixiang
</n-tab-pane>
</n-tabs>
</template>
Best Practices
-
Use appropriate type: Choose tab type based on context - card for editable, segment for toggle groups
-
Set default-value: Always set default-value to avoid Vue slot warnings
-
Use display-directive wisely: Use show to preserve state, if for fresh content
-
Implement before-leave: Validate form data before allowing tab switch
-
Animated transitions: Enable animated for better UX
-
Limit tab count: Keep tabs manageable, use scrolling or dropdowns for many tabs