20260720172840

This commit is contained in:
oneao committed 2026-07-20 17:28:47 +08:00
1 parent cda7f16d3a
commit 94207c77ff
3117 files changed
+201407 -1236

No files matched your search

@@ -0,0 +1,57 @@
# _semantic
## Source
```vue
<script setup lang="ts">
import { computed } from 'vue'
import { SemanticPreview } from '@/components/semantic'
import { useComponentLocale } from '@/composables/use-locale'
import { locales } from '../locales'
const { t } = useComponentLocale(locales)
const semantics = computed(() => [
{ name: 'root', desc: t('root') },
{ name: 'header', desc: t('header') },
{ name: 'item', desc: t('item') },
{ name: 'indicator', desc: t('indicator') },
{ name: 'body', desc: t('body') },
{ name: 'content', desc: t('content') },
{ name: 'popup.root', desc: t('popup.root') },
])
const items = computed(() =>
Array.from({ length: 30 }, (_, i) => {
const id = String(i)
return {
label: `Tab-${id}`,
key: id,
disabled: i === 28,
content: `Content of tab ${id}`,
}
}),
)
</script>
<template>
<SemanticPreview
component-name="Tabs"
:semantics="semantics"
>
<template #default="{ classes }">
<a-tabs
default-active-key="1"
:style="{ height: '220px', width: '100%' }"
:styles="{
popup: {
root: { background: '#fff' },
},
}"
:items="items"
:classes="classes"
/>
</template>
</SemanticPreview>
</template>
```
@@ -0,0 +1,35 @@
# Basic
## Description (en-US)
Default activate first tab.
## Source
```vue
<script setup lang="ts">
import type { TabsProps } from 'antdv-next'
const items: TabsProps['items'] = [
{
key: '1',
label: 'Tab 1',
content: 'Content of Tab Pane 1',
},
{
key: '2',
label: 'Tab 2',
content: 'Content of Tab Pane 2',
},
{
key: '3',
label: 'Tab 3',
content: 'Content of Tab Pane 3',
},
]
</script>
<template>
<a-tabs :items="items" />
</template>
```
@@ -0,0 +1,30 @@
# Card type tab
## Description (en-US)
Another type of Tabs, which doesn't support vertical mode.
## Source
```vue
<script setup lang="ts">
import type { TabsProps } from 'antdv-next'
function onChange(key: string) {
console.log(key)
}
const items: TabsProps['items'] = Array.from({ length: 3 }).map((_, i) => {
const id = String(i + 1)
return {
key: id,
label: `Tab ${id}`,
content: `Content of Tab Pane ${id}`,
}
})
</script>
<template>
<a-tabs default-active-key="1" type="card" :items="items" @change="onChange" />
</template>
```
@@ -0,0 +1,26 @@
# Centered
## Description (en-US)
Centered tabs.
## Source
```vue
<script setup lang="ts">
import type { TabsProps } from 'antdv-next'
const items: TabsProps['items'] = Array.from({ length: 3 }).map((_, i) => {
const id = String(i + 1)
return {
key: id,
label: `Tab ${id}`,
content: `Content of Tab Pane ${id}`,
}
})
</script>
<template>
<a-tabs centered :items="items" />
</template>
```
@@ -0,0 +1,81 @@
# Customized trigger of new tab
## Description (en-US)
Hide default plus icon, and bind event for customized trigger.
## Source
```vue
<script setup lang="ts">
import { ref } from 'vue'
interface TabItem {
key: string
label: string
content: string
}
const defaultPanes: TabItem[] = Array.from({ length: 2 }).map((_, index) => {
const id = String(index + 1)
return {
key: id,
label: `Tab ${id}`,
content: `Content of Tab Pane ${index + 1}`,
}
})
const activeKey = ref(defaultPanes[0]?.key ?? '1')
const items = ref<TabItem[]>([...defaultPanes])
let newTabIndex = 0
function onChange(key: string) {
activeKey.value = key
}
function add() {
const newActiveKey = `newTab${newTabIndex++}`
items.value = [...items.value, { key: newActiveKey, label: 'New Tab', content: 'New Tab Pane' }]
activeKey.value = newActiveKey
}
function remove(targetKey: string) {
const targetIndex = items.value.findIndex(pane => pane.key === targetKey)
const newPanes = items.value.filter(pane => pane.key !== targetKey)
if (newPanes.length && targetKey === activeKey.value) {
const nextPane = newPanes[targetIndex === newPanes.length ? targetIndex - 1 : targetIndex]
if (nextPane) {
activeKey.value = nextPane.key
}
}
items.value = newPanes
}
function onEdit(targetKey: string | MouseEvent | KeyboardEvent, action: 'add' | 'remove') {
if (action === 'add') {
add()
}
else {
remove(targetKey as string)
}
}
</script>
<template>
<div>
<div style="margin-bottom: 16px;">
<a-button @click="add">
ADD
</a-button>
</div>
<a-tabs
v-model:active-key="activeKey"
type="editable-card"
hide-add
:items="items"
@change="onChange"
@edit="onEdit"
/>
</div>
</template>
```
@@ -0,0 +1,44 @@
# Indicator
## Description (en-US)
Set `indicator` prop to custom indicator size and align.
## Source
```vue
<script setup lang="ts">
import type { TabsProps } from 'antdv-next'
import { ref } from 'vue'
const items: TabsProps['items'] = [
{ key: '1', label: 'Tab 1', content: 'Content of Tab Pane 1' },
{ key: '2', label: 'Tab 2', content: 'Content of Tab Pane 2' },
{ key: '3', label: 'Tab 3', content: 'Content of Tab Pane 3' },
]
type Align = 'start' | 'center' | 'end'
const alignValue = ref<Align>('center')
function onChange(key: string) {
console.log(key)
}
</script>
<template>
<div>
<a-segmented
v-model:value="alignValue"
style="margin-bottom: 8px;"
:options="['start', 'center', 'end']"
/>
<a-tabs
default-active-key="1"
:items="items"
:indicator="{ size: (origin: number) => origin - 20, align: alignValue }"
@change="onChange"
/>
</div>
</template>
```
@@ -0,0 +1,92 @@
# Draggable Tabs
## Description (en-US)
Use `renderTabBar` with drag support to reorder tabs.
## Source
```vue
<script setup lang="ts">
import type { TabsProps } from 'antdv-next'
import { ref } from 'vue'
type TabItem = NonNullable<TabsProps['items']>[number]
const items = ref<TabItem[]>([
{ key: '1', label: 'Tab 1', content: 'Content of Tab Pane 1' },
{ key: '2', label: 'Tab 2', content: 'Content of Tab Pane 2' },
{ key: '3', label: 'Tab 3', content: 'Content of Tab Pane 3' },
])
const draggingKey = ref<string | null>(null)
function getNodeKey(node: any) {
return String(node?.props?.['data-node-key'] ?? '')
}
function handleDragStart(key: string, event: DragEvent) {
if (!key) {
return
}
draggingKey.value = key
event.dataTransfer?.setData('text/plain', key)
event.dataTransfer?.setDragImage?.(event.currentTarget as Element, 0, 0)
}
function handleDragEnd() {
draggingKey.value = null
}
function handleDrop(overKey: string, event: DragEvent) {
const activeKey = event.dataTransfer?.getData('text/plain')
if (!activeKey || !overKey || activeKey === overKey) {
return
}
const activeIndex = items.value.findIndex(item => String(item.key) === activeKey)
const overIndex = items.value.findIndex(item => String(item.key) === overKey)
if (activeIndex < 0 || overIndex < 0) {
return
}
const next = items.value.slice()
const [moved] = next.splice(activeIndex, 1)
if (!moved) {
return
}
next.splice(overIndex, 0, moved)
items.value = next
}
</script>
<template>
<a-tabs :items="items" :styles="{ item: { cursor: 'move' } }">
<template #renderTabBar="{ TabNavListComponent, props }">
<component :is="TabNavListComponent" v-bind="props">
<template #default="node">
<div
class="draggable-tab" :class="{ 'draggable-tab--dragging': draggingKey === getNodeKey(node) }"
draggable="true" @dragstart="(event) => handleDragStart(getNodeKey(node), event)" @dragover.prevent
@drop="(event) => handleDrop(getNodeKey(node), event)" @dragend="handleDragEnd"
>
<component :is="node" />
</div>
</template>
</component>
</template>
</a-tabs>
</template>
<style>
.draggable-tab {
margin-left: var(--ant-tabs-horizontal-item-gutter);
}
.draggable-tab:first-child {
margin-left: 0;
}
.draggable-tab--dragging {
opacity: 0.6;
}
</style>
```
@@ -0,0 +1,47 @@
# Customized bar of tab
## Description (en-US)
Use `renderTabBar` with a sticky container to pin the tab bar.
## Source
```vue
<script setup lang="ts">
import { theme } from 'antdv-next'
import { ref } from 'vue'
interface TabItem {
key: string
label: string
content: string
style?: Record<string, any>
}
const items: TabItem[] = Array.from({ length: 3 }).map((_, i) => {
const id = String(i + 1)
return {
key: id,
label: `Tab ${id}`,
content: `Content of Tab Pane ${id}`,
style: i === 0 ? { height: '200px' } : undefined,
}
})
const { token } = theme.useToken()
const activeKey = ref('1')
</script>
<template>
<a-tabs v-model:active-key="activeKey" :items="items">
<template #renderTabBar="{ TabNavListComponent, props }">
<div
style="position: sticky; top: 64px; z-index: 1;"
:style="{ background: token.colorBgContainer }"
>
<component :is="TabNavListComponent" v-bind="props" />
</div>
</template>
</a-tabs>
</template>
```
@@ -0,0 +1,36 @@
# Disabled
## Description (en-US)
Disabled a tab.
## Source
```vue
<script setup lang="ts">
import type { TabsProps } from 'antdv-next'
const items: TabsProps['items'] = [
{
key: '1',
label: 'Tab 1',
content: 'Tab 1',
},
{
key: '2',
label: 'Tab 2',
content: 'Tab 2',
disabled: true,
},
{
key: '3',
label: 'Tab 3',
content: 'Tab 3',
},
]
</script>
<template>
<a-tabs default-active-key="1" :items="items" />
</template>
```
@@ -0,0 +1,80 @@
# Add & close tab
## Description (en-US)
Only card type Tabs support adding & closable. Use `closable={false}` to disable close.
## Source
```vue
<script setup lang="ts">
import { ref } from 'vue'
interface TabItem {
key: string
label: string
content: string
closable?: boolean
}
const initialItems: TabItem[] = [
{ key: '1', label: 'Tab 1', content: 'Content of Tab 1' },
{ key: '2', label: 'Tab 2', content: 'Content of Tab 2' },
{ key: '3', label: 'Tab 3', content: 'Content of Tab 3', closable: false },
]
const activeKey = ref(initialItems[0]?.key ?? '1')
const items = ref<TabItem[]>([...initialItems])
let newTabIndex = 0
function onChange(newActiveKey: string) {
activeKey.value = newActiveKey
}
function add() {
const newActiveKey = `newTab${newTabIndex++}`
items.value = [...items.value, { key: newActiveKey, label: 'New Tab', content: 'Content of new Tab' }]
activeKey.value = newActiveKey
}
function remove(targetKey: string) {
let newActiveKey = activeKey.value
let lastIndex = -1
items.value.forEach((item, i) => {
if (item.key === targetKey) {
lastIndex = i - 1
}
})
const newPanes = items.value.filter(item => item.key !== targetKey)
if (newPanes.length && newActiveKey === targetKey) {
if (lastIndex >= 0 && newPanes[lastIndex]) {
newActiveKey = newPanes[lastIndex]!.key!
}
else if (newPanes[0]) {
newActiveKey = newPanes[0]!.key!
}
}
items.value = newPanes
activeKey.value = newActiveKey
}
function onEdit(targetKey: string | MouseEvent | KeyboardEvent, action: 'add' | 'remove') {
if (action === 'add') {
add()
}
else {
remove(targetKey as string)
}
}
</script>
<template>
<a-tabs
v-model:active-key="activeKey"
type="editable-card"
:items="items"
@change="onChange"
@edit="onEdit"
/>
</template>
```
@@ -0,0 +1,79 @@
# Extra content
## Description (en-US)
You can add extra actions to the right or left or even both side of Tabs.
## Source
```vue
<script setup lang="ts">
import type { TabsProps } from 'antdv-next'
import { computed, h, ref, resolveComponent } from 'vue'
type PositionType = 'left' | 'right'
const options = ['left', 'right']
const items: TabsProps['items'] = Array.from({ length: 3 }).map((_, i) => {
const id = String(i + 1)
return {
key: id,
label: `Tab ${id}`,
content: `Content of tab ${id}`,
}
})
const position = ref<PositionType[]>(['left', 'right'])
const slot = computed(() => {
if (position.value.length === 0) {
return null
}
const result: Record<string, boolean> = {}
position.value.forEach((dir) => {
result[dir] = true
})
return result
})
const extraContent = computed(() =>
h(resolveComponent('a-button') as any, null, { default: () => 'Extra Action' }),
)
</script>
<template>
<div>
<a-tabs :items="items" :tab-bar-extra-content="extraContent" />
<br>
<br>
<br>
<div>You can also specify its direction or both side</div>
<a-divider />
<a-checkbox-group v-model:value="position" :options="options" />
<br>
<br>
<a-tabs :items="items">
<template v-if="slot?.left" #leftExtra>
<a-button class="tabs-extra-demo-button">
Left Extra Action
</a-button>
</template>
<template v-if="slot?.right" #rightExtra>
<a-button>Right Extra Action</a-button>
</template>
</a-tabs>
</div>
</template>
<style scoped>
.tabs-extra-demo-button {
margin-inline-end: 16px;
}
.ant-row-rtl .tabs-extra-demo-button {
margin-inline-end: 0;
margin-inline-start: 16px;
}
</style>
```
@@ -0,0 +1,31 @@
# Icon
## Description (en-US)
The Tab with Icon.
## Source
```vue
<script setup lang="ts">
import type { TabsProps } from 'antdv-next'
import { AndroidOutlined, AppleOutlined } from '@antdv-next/icons'
import { h } from 'vue'
const icons = [AppleOutlined, AndroidOutlined]
const items: TabsProps['items'] = icons.map((Icon, i) => {
const id = String(i + 1)
return {
key: id,
label: `Tab ${id}`,
content: `Tab ${id}`,
icon: () => h(Icon),
}
})
</script>
<template>
<a-tabs default-active-key="2" :items="items" />
</template>
```
@@ -0,0 +1,53 @@
# Placement
## Description (en-US)
Tab's placement: start, end, top or bottom. Will auto switch to `top` in mobile.
## Source
```vue
<script setup lang="ts">
import { ref } from 'vue'
type TabPlacement = 'top' | 'bottom' | 'start' | 'end'
interface TabItem {
key: string
label: string
content: string
}
const tabPlacement = ref<TabPlacement>('start')
const items: TabItem[] = Array.from({ length: 3 }).map((_, i) => {
const id = String(i + 1)
return {
key: id,
label: `Tab ${id}`,
content: `Content of Tab ${id}`,
}
})
</script>
<template>
<a-space style="margin-bottom: 24px;">
Tab placement:
<a-radio-group v-model:value="tabPlacement">
<a-radio-button value="top">
top
</a-radio-button>
<a-radio-button value="bottom">
bottom
</a-radio-button>
<a-radio-button value="start">
start
</a-radio-button>
<a-radio-button value="end">
end
</a-radio-button>
</a-radio-group>
</a-space>
<a-tabs :tab-placement="tabPlacement" :items="items" />
</template>
```
@@ -0,0 +1,114 @@
# Size
## Description (en-US)
Large size tabs are usually used in page header, and small size could be used in Modal.
## Source
```vue
<script setup lang="ts">
import { ref } from 'vue'
type TabSize = 'small' | 'middle' | 'large'
interface TabItem {
key: string
label: string
content: string
}
const size = ref<TabSize>('small')
const activeKey = ref('1')
const items = ref<TabItem[]>([
{ key: '1', label: 'Tab 1', content: 'Content of editable tab 1' },
{ key: '2', label: 'Tab 2', content: 'Content of editable tab 2' },
{ key: '3', label: 'Tab 3', content: 'Content of editable tab 3' },
])
const staticItems: TabItem[] = Array.from({ length: 3 }).map((_, i) => {
const id = String(i + 1)
return {
key: id,
label: `Tab ${id}`,
content: `Content of tab ${id}`,
}
})
const cardItems: TabItem[] = Array.from({ length: 3 }).map((_, i) => {
const id = String(i + 1)
return {
key: id,
label: `Card Tab ${id}`,
content: `Content of card tab ${id}`,
}
})
function add() {
const newKey = String(items.value.length + 1)
items.value.push({
key: newKey,
label: `Tab ${newKey}`,
content: `Content of editable tab ${newKey}`,
})
activeKey.value = newKey
}
function remove(targetKey: string) {
const targetIndex = items.value.findIndex(item => item.key === targetKey)
const newItems = items.value.filter(item => item.key !== targetKey)
if (newItems.length && targetKey === activeKey.value) {
const newIndex = targetIndex === newItems.length ? targetIndex - 1 : targetIndex
activeKey.value = newItems[newIndex]?.key ?? newItems[0]?.key ?? '1'
}
items.value = newItems
}
function onEdit(targetKey: string | MouseEvent | KeyboardEvent, action: 'add' | 'remove') {
if (action === 'add') {
add()
}
else if (typeof targetKey === 'string') {
remove(targetKey)
}
}
</script>
<template>
<div>
<a-radio-group v-model:value="size" style="margin-bottom: 16px;">
<a-radio-button value="small">
Small
</a-radio-button>
<a-radio-button value="middle">
Middle
</a-radio-button>
<a-radio-button value="large">
Large
</a-radio-button>
</a-radio-group>
<a-tabs
default-active-key="1"
:size="size"
style="margin-bottom: 32px;"
:items="staticItems"
/>
<a-tabs
default-active-key="1"
type="card"
:size="size"
style="margin-bottom: 32px;"
:items="cardItems"
/>
<a-tabs
v-model:active-key="activeKey"
type="editable-card"
:size="size"
:items="items"
@edit="onEdit"
/>
</div>
</template>
```
@@ -0,0 +1,55 @@
# Slide
## Description (en-US)
In order to fit in more tabs, they can slide left and right (or up and down).
## Source
```vue
<script setup lang="ts">
import { ref } from 'vue'
type TabPlacement = 'top' | 'left'
interface TabItem {
key: string
label: string
content: string
disabled?: boolean
}
const mode = ref<TabPlacement>('top')
const items: TabItem[] = Array.from({ length: 30 }, (_, i) => {
const id = String(i)
return {
key: id,
label: `Tab-${id}`,
content: `Content of tab ${id}`,
disabled: i === 28,
}
})
const activeKey = ref('0')
</script>
<template>
<div>
<a-radio-group v-model:value="mode" style="margin-bottom: 8px;">
<a-radio-button value="top">
Horizontal
</a-radio-button>
<a-radio-button value="left">
Vertical
</a-radio-button>
</a-radio-group>
<a-tabs
v-model:active-key="activeKey"
:tab-placement="mode"
style="height: 220px;"
:items="items"
/>
</div>
</template>
```
@@ -0,0 +1,56 @@
# Custom semantic dom styling
## Description (en-US)
## Source
```vue
<script setup lang="ts">
import type { TabsProps } from 'antdv-next'
const items: TabsProps['items'] = [
{ key: '1', label: 'Tab 1', content: 'Content of Tab Pane 1' },
{ key: '2', label: 'Tab 2', content: 'Content of Tab Pane 2' },
{ key: '3', label: 'Tab 3', content: 'Content of Tab Pane 3' },
]
const classes: TabsProps['classes'] = {
root: 'custom-tabs-root',
}
const stylesObject: TabsProps['styles'] = {
root: { borderWidth: '2px', borderStyle: 'dashed', padding: '16px', marginBottom: '10px' },
header: { backgroundColor: 'rgba(245,245,245,0.5)' },
item: { fontWeight: 'bold', color: '#1890ff', padding: `6px 10px` },
indicator: { backgroundColor: 'rgba(255,77,79, 0.3)', height: '4px' },
body: { backgroundColor: 'rgba(230,247,255,0.8)' },
content: { padding: '16px' },
}
const stylesFn: TabsProps['styles'] = (info) => {
if (info.props.type === 'card') {
return {
root: { backgroundColor: 'rgba(250,250,250, 0.8)', borderColor: '#d9d9d9' },
header: { textAlign: 'start' },
} satisfies TabsProps['styles']
}
return {}
}
</script>
<template>
<a-flex vertical gap="middle">
<a-tabs :items="items" :classes="classes" :styles="stylesObject" />
<a-tabs type="card" :items="items" :classes="classes" :styles="stylesFn" />
</a-flex>
</template>
<style>
.custom-tabs-root {
border-width: 2px;
border-style: dashed;
padding: 16px;
margin-bottom: 10px;
}
</style>
```
@@ -0,0 +1,108 @@
---
title: Tabs
description: Tabs make it easy to explore and switch between different views.
---
## When To Use
Antdv Next has 3 types of Tabs for different situations.
- Card Tabs: for managing too many closeable views.
- Normal Tabs: for functional aspects of a page.
- [Radio.Button](../radio/docs.md/#radio-demo-radiobutton): for secondary tabs.
## Demos
| Demo | Path |
| --- | --- |
| Basic | demo/basic.md |
| Disabled | demo/disabled.md |
| Centered | demo/centered.md |
| Icon | demo/icon.md |
| Indicator | demo/custom-indicator.md |
| Slide | demo/slide.md |
| Extra content | demo/extra.md |
| Size | demo/size.md |
| Placement | demo/placement.md |
| Card type tab | demo/card.md |
| Add & close tab | demo/editable-card.md |
| Customized trigger of new tab | demo/custom-add-trigger.md |
| Customized bar of tab | demo/custom-tab-bar.md |
| Draggable Tabs | demo/custom-tab-bar-node.md |
| Custom semantic dom styling | demo/style-class.md |
## API
### Property
Common props ref:[Common props](../../docs/vue/common-props.md)
| Property | Description | Type | Default | Version | [Global Config](../config-provider/docs.md#component-config) |
| --- | --- | --- | --- | --- | --- |
| activeKey | Current TabPane's key, support `v-model:active-key` | string | - | - | × |
| addIcon | Customize add icon, only works with `type="editable-card"` | VueNode | `<PlusOutlined />` | - | ✓ |
| animated | Whether to change tabs with animation | boolean \| \{ inkBar: boolean, tabPane: boolean \} | \{ inkBar: true, tabPane: false \} | - | × |
| centered | Centers tabs | boolean | false | - | × |
| classes | Customize class for each semantic structure inside the component. Supports object or function | TabsClassNamesType | - | - | ✓ |
| defaultActiveKey | Initial active TabPane's key, if `activeKey` is not set | string | `The key of first tab` | - | × |
| hideAdd | Hide plus icon or not. Only works while `type="editable-card"` | boolean | false | - | × |
| indicator | Customize `size` and `align` of indicator | \{ size?: number \| (origin: number) => number; align?: `start` \| `center` \| `end` \} | - | - | ✓ |
| items | Configure tab content | TabItemType[] | [] | - | × |
| more | Customize the collapse menu | MoreProps | \{ icon: `<EllipsisOutlined />`, trigger: 'hover' \} | - | ✓ |
| moreIcon | Custom icon of the collapse menu | VueNode | `<EllipsisOutlined />` | - | ✓ |
| removeIcon | The custom icon of remove, only works with `type="editable-card"` | VueNode | `<CloseOutlined />` | - | ✓ |
| renderTabBar | Replace the TabBar | (ctx: \{ props: any; TabNavListComponent: any \}) => VueNode | - | - | × |
| size | Preset tab bar size | `large` \| `middle` \| `small` | `middle` | - | × |
| styles | Customize inline style for each semantic structure inside the component. Supports object or function | TabsStylesType | - | - | ✓ |
| tabBarExtraContent | Extra content in tab bar | VueNode \| \{ left?: VueNode, right?: VueNode \} | - | - | × |
| tabBarGutter | The gap between tabs | number | - | - | × |
| tabBarStyle | Tab bar style object | CSSProperties | - | - | × |
| tabPlacement | Placement of tabs | `top` \| `end` \| `bottom` \| `start` | `top` | - | × |
| destroyOnHidden | Whether destroy inactive TabPane when change tab | boolean | false | - | × |
| type | Basic style of tabs | `line` \| `card` \| `editable-card` | `line` | - | × |
### TabItemType
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| closeIcon | Customize close icon in TabPane's head. Setting to `null` or `false` hides the close button | VueNode | - | - |
| destroyOnHidden | Whether destroy inactive TabPane when change tab | boolean | false | - |
| disabled | Set TabPane disabled | boolean | false | - |
| forceRender | Forced render of content in tabs, not lazy render after clicking on tabs | boolean | false | - |
| key | TabPane's key | string | - | - |
| label | Tab header text element | VueNode | - | - |
| icon | Tab header icon element | VueNode | - | - |
| content | Tab content element | VueNode | - | - |
| closable | Whether a close (x) button is visible, only works while `type="editable-card"` | boolean | true | - |
### MoreProps
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| icon | The custom icon | VueNode | - | - |
| DropdownProps | Dropdown props | DropdownProps | - | - |
### Events
| Event | Description | Type | Version |
| --- | --- | --- | --- |
| change | Callback executed when active tab is changed | (activeKey: string) => void | - |
| edit | Callback executed when tab is added or removed. Only works while `type="editable-card"` | (e: MouseEvent \| KeyboardEvent \| string, action: 'add' \| 'remove') => void | - |
| tabClick | Callback executed when tab is clicked | (key: string, event: MouseEvent) => void | - |
| tabScroll | Trigger when tab scroll | (\{ direction: `left` \| `right` \| `top` \| `bottom` \}) => void | - |
### Slots
| Slot | Description | Type | Version |
| --- | --- | --- | --- |
| addIcon | Customize add icon, only works with `type="editable-card"` | () => any | - |
| moreIcon | Custom collapse menu icon | () => any | - |
| removeIcon | The custom icon of remove, only works with `type="editable-card"` | () => any | - |
| labelRender | Custom label render | (args: \{ item: TabItemType; index: number \}) => any | - |
| contentRender | Custom content render | (args: \{ item: TabItemType; index: number \}) => any | - |
| renderTabBar | Replace the TabBar | (args: \{ props: any; TabNavListComponent: any \}) => any | - |
| rightExtra | Extra content on the right | () => any | - |
| leftExtra | Extra content on the left | () => any | - |
### Methods
| Method | Description | Type | Version |
| --- | --- | --- | --- |
| nativeElement | Root element | any | - |
## Semantic DOM
| _semantic | demo/_semantic.md |
@@ -0,0 +1,51 @@
# tabs Token
Use these variables through `theme.components.Tabs`. This document lists definitions only and does not include values.
```vue
<a-config-provider
:theme="{
token: {
// Global token configuration
},
components: {
Tabs: {
// Token name: value
},
},
}"
>
...
</a-config-provider>
```
## Token List
| Token | Type | Description |
| --- | --- | --- |
| `zIndexPopup` | `number` | z-index of dropdown menu |
| `cardBg` | `string` | Background color of card tab |
| `cardHeight` | `number` | Height of card tab |
| `cardHeightSM` | `number` | Height of small card tab |
| `cardHeightLG` | `number` | Height of large card tab |
| `cardPadding` | `string` | Padding of card tab |
| `cardPaddingSM` | `string` | Padding of small card tab |
| `cardPaddingLG` | `string` | Padding of large card tab |
| `titleFontSize` | `number` | Font size of title |
| `titleFontSizeLG` | `number` | Font size of large title |
| `titleFontSizeSM` | `number` | Font size of small title |
| `inkBarColor` | `string` | Color of indicator |
| `horizontalMargin` | `string` | Horizontal margin of horizontal tab |
| `horizontalItemGutter` | `number` | Horizontal gutter of horizontal tab |
| `horizontalItemMargin` | `string` | Horizontal margin of horizontal tab item |
| `horizontalItemMarginRTL` | `string` | Horizontal margin of horizontal tab item (RTL) |
| `horizontalItemPadding` | `string` | Horizontal padding of horizontal tab item |
| `horizontalItemPaddingLG` | `string` | Horizontal padding of large horizontal tab item |
| `horizontalItemPaddingSM` | `string` | Horizontal padding of small horizontal tab item |
| `verticalItemPadding` | `string` | Vertical padding of vertical tab item |
| `verticalItemMargin` | `string` | Vertical margin of vertical tab item |
| `itemColor` | `string` | Text color of tab |
| `itemActiveColor` | `string` | Text color of active tab |
| `itemHoverColor` | `string` | Text color of hover tab |
| `itemSelectedColor` | `string` | Text color of selected tab |
| `cardGutter` | `number` | Gutter of card tab |