> Leaf UI 0.6.0 · Package: @ifhover/leaf-ui · Source: b30c3d3a8fa9c5e15d0d0522cebfbd33f60c6b06
> Browser documentation: https://ifhover.github.io/leaf-ui/v/0.6.0/components/tabs.html

> For AI agents: the complete documentation index is available at https://ifhover.github.io/leaf-ui/v/0.6.0/llms.txt, the full documentation bundle is available at https://ifhover.github.io/leaf-ui/v/0.6.0/llms-full.txt.

# Tabs 标签页

在同一区域切换不同内容。

切换时正文和内容区域高度立即更新，不使用过渡动画；标签栏的选中指示线保留移动效果。

卡片样式的标签栏默认随标签内容调整宽度，空间不足时在栏内滚动。`size` 控制整个标签栏的尺寸，正文区域使用可用宽度。

## 基础用法


线形标签

概览

设置

历史

查看项目活动、成员和最近更新。

卡片标签

概览

设置

历史

查看项目活动、成员和最近更新。

纵向标签

概览

设置

历史

查看项目活动、成员和最近更新。

basic.tsx

复制代码

```tsx lineNumbers file="../../src/examples/tabs/basic.tsx"
import type { TabItem } from '@ifhover/leaf-ui';

import { Input, Space, Tabs } from '@ifhover/leaf-ui';

import { ChartNoAxesColumn, Settings } from 'lucide-react';

const items: readonly TabItem[] = [
  {
    key: 'overview',
    label: '概览',
    icon: <ChartNoAxesColumn />,
    children: '查看项目活动、成员和最近更新。',
  },
  {
    key: 'settings',
    label: '设置',
    icon: <Settings />,
    children: <Input aria-label="项目名称" placeholder="输入内容后切换，内容会保留" />,
  },
  { key: 'history', label: '历史', disabled: true, children: null },
];

export function TabsBasic() {
  return (
    <Space direction="vertical" align="stretch">
      <Space direction="vertical" align="stretch" size="sm">
        <span>线形标签</span>
        <Tabs aria-label="项目信息" items={items} />
      </Space>
      <Space direction="vertical" align="stretch" size="sm">
        <span>卡片标签</span>
        <Tabs aria-label="卡片标签" items={items} type="card" />
      </Space>
      <Space direction="vertical" align="stretch" size="sm">
        <span>纵向标签</span>
        <Tabs aria-label="纵向标签" items={items} placement="left" />
      </Space>
    </Space>
  );
}
```

展开代码

## 不同尺寸

线形与卡片标签分别展示小、默认和大尺寸。


线形标签

小尺寸

概览

成员

查看项目的最近更新。

默认尺寸

概览

成员

查看项目的最近更新。

大尺寸

概览

成员

查看项目的最近更新。

卡片标签

小尺寸

概览

成员

查看项目的最近更新。

默认尺寸

概览

成员

查看项目的最近更新。

大尺寸

概览

成员

查看项目的最近更新。

sizes.tsx

复制代码

```tsx lineNumbers file="../../src/examples/tabs/sizes.tsx"
import { Grid, Space, Tabs, Text } from '@ifhover/leaf-ui';

const items = [
  { key: 'overview', label: '概览', children: '查看项目的最近更新。' },
  { key: 'members', label: '成员', children: '管理项目成员和访问权限。' },
];

const labels = { sm: '小尺寸', md: '默认尺寸', lg: '大尺寸' };

const variants = [
  { type: 'line', label: '线形标签' },
  { type: 'card', label: '卡片标签' },
] as const;

export function TabsSizes() {
  return (
    <Grid columns={{ xs: 1, sm: 2 }} gap={24}>
      {variants.map(({ type, label }) => (
        <Space key={type} direction="vertical" align="stretch" size="lg">
          <Text strong>{label}</Text>
          {(['sm', 'md', 'lg'] as const).map((size) => (
            <Space key={size} direction="vertical" align="stretch" size="sm">
              <span>{labels[size]}</span>
              <Tabs
                aria-label={`${label} · ${labels[size]}`}
                items={items}
                type={type}
                size={size}
              />
            </Space>
          ))}
        </Space>
      ))}
    </Grid>
  );
}
```

展开代码

## 可关闭标签页

点击加号新增标签页。全部关闭后组件隐藏，可使用示例中的新增按钮重新打开。


项目一

项目二

项目一的内容

closable.tsx

复制代码

```tsx lineNumbers file="../../src/examples/tabs/closable.tsx"
import { Button, Space, type TabItem, Tabs } from '@ifhover/leaf-ui';

import { useRef, useState } from 'react';

export function TabsClosable() {
  const sequence = useRef(2);
  const [items, setItems] = useState<TabItem[]>([
    { key: '1', label: '项目一', children: '项目一的内容', closable: true },
    { key: '2', label: '项目二', children: '项目二的内容', closable: true },
  ]);
  const addTab = () => {
    const key = String(++sequence.current);
    setItems((list) => [
      ...list,
      { key, label: `项目 ${key}`, children: `项目 ${key} 的内容`, closable: true },
    ]);
  };
  return (
    <Space direction="vertical" align="stretch">
      <Tabs
        aria-label="可关闭标签页"
        items={items}
        type="card"
        onClose={(key) => setItems((list) => list.filter((item) => item.key !== key))}
        onAdd={addTab}
        addLabel="新增标签页"
      />
      {items.length === 0 && (
        <Space>
          <Button variant="outline" onClick={addTab}>
            新增标签页
          </Button>
        </Space>
      )}
    </Space>
  );
}
```

展开代码

## 扩展用法


项目 1

项目 2

项目 3

项目 4

项目 5

项目 6

项目 1 内容

extensions.tsx

复制代码

```tsx lineNumbers file="../../src/examples/tabs/extensions.tsx"
import { Button, Space, type TabItem, Tabs } from '@ifhover/leaf-ui';

import { useRef, useState } from 'react';

export function ExtensionDemo() {
  const count = useRef(7);
  const [items, setItems] = useState<TabItem[]>(
    Array.from({ length: 6 }, (_, i) => ({
      key: String(i),
      label: `项目 ${i + 1}`,
      children: `项目 ${i + 1} 内容`,
      closable: true,
    })),
  );
  const addTab = () => {
    const id = String(count.current++);
    setItems((current) => [
      ...current,
      { key: id, label: `项目 ${id}`, children: '新项目', closable: true },
    ]);
  };
  return (
    <Space direction="vertical" align="stretch">
      <Tabs
        aria-label="可排序标签页"
        items={items}
        sortable
        onReorder={setItems}
        onAdd={addTab}
        onClose={(key) => setItems((current) => current.filter((item) => item.key !== key))}
      />
      {items.length === 0 && (
        <Space>
          <Button variant="outline" onClick={addTab}>
            新增标签页
          </Button>
        </Space>
      )}
    </Space>
  );
}
```

展开代码

## 底部与右侧


底部标签页

Design

Tokens

Design settings

右侧标签页

Design

Tokens

Design settings

capabilities.tsx

复制代码

```tsx lineNumbers file="../../src/examples/tabs/capabilities.tsx"
import { Space, Tabs } from '@ifhover/leaf-ui';

const items = [
  { key: 'design', label: 'Design', children: 'Design settings' },
  { key: 'tokens', label: 'Tokens', children: 'Theme tokens' },
];

export function Capabilities() {
  return (
    <Space direction="vertical" align="stretch">
      <Space direction="vertical" align="stretch" size="sm">
        <span>{'底部标签页'}</span>
        <Tabs
          aria-label={'底部标签页'}
          placement="bottom"
          items={items}
        />
      </Space>
      <Space direction="vertical" align="stretch" size="sm">
        <span>{'右侧标签页'}</span>
        <Tabs aria-label={'右侧标签页'} placement="right" items={items} />
      </Space>
    </Space>
  );
}
```

展开代码

## Tabs API

| 属性                 | 类型                                                            | 默认值           | 说明                           |
| ------------------ | ------------------------------------------------------------- | ------------- | ---------------------------- |
| `items`            | `readonly `[`TabItem`](#tabitem)`[]`                          | 必填            | 标签页列表；为空时不渲染组件               |
| `activeKey`        | `string`                                                      | 首个可用项         | 受控激活项 / 初始项                  |
| `defaultActiveKey` | `string`                                                      | 首个可用项         | 受控激活项 / 初始项                  |
| `onChange`         | `(key: string) => void`                                       | —             | 激活项变化                        |
| `type`             | `'line' \| 'card'`                                            | `'line'`      | 标签形态                         |
| `placement`        | `'top' \| 'bottom' \| 'left' \| 'right'`                      | `'top'`       | 标签栏位置                        |
| `size`             | `'sm' \| 'md' \| 'lg'`                                        | `'md'`        | 标签尺寸；卡片样式包含标签栏的内边距和边框        |
| `activationMode`   | `'automatic' \| 'manual'`                                     | `'automatic'` | 方向键直接激活 / 回车或空格激活            |
| `destroyInactive`  | `boolean`                                                     | `false`       | 切走时卸载内容                      |
| `extra`            | `ReactNode`                                                   | —             | 标签栏附加内容                      |
| `onClose`          | `(key: string, event: MouseEvent<HTMLButtonElement>) => void` | —             | 请求关闭，由应用移除 items 中的项；可阻止默认切换 |
| `onAdd`            | `() => void`                                                  | —             | 添加页签，传入后显示添加按钮               |
| `addLabel`         | `string`                                                      | —             | 添加按钮的可访问名称                   |
| `overflow`         | `boolean`                                                     | `true`        | 溢出页签收进更多菜单                   |
| `sortable`         | `boolean`                                                     | `false`       | 启用排序，配合 onReorder 使用         |
| `onReorder`        | `(items: `[`TabItem`](#tabitem)`[]) => void`                  | —             | 返回排序后的页签                     |

## TabItem

| 属性         | 类型          | 默认值     | 说明                 |
| ---------- | ----------- | ------- | ------------------ |
| `key`      | `string`    | 必填      | 必需。唯一标识            |
| `label`    | `ReactNode` | 必填      | 必需。标签名称            |
| `children` | `ReactNode` | 必填      | 必需。对应内容            |
| `disabled` | `boolean`   | `false` | 禁用交互。              |
| `icon`     | `ReactNode` | —       | 前置图标               |
| `closable` | `boolean`   | `false` | 展示关闭按钮，需配合 onClose |

## 类型

定义组件属性或组装列表时可导入相关类型。

```ts
import type { TabsProps, TabItem } from '@ifhover/leaf-ui';
```

## 使用说明

内容首次访问时挂载，默认保留访问过的内容和输入状态。方向键会跳过禁用项，Home / End 跳至首尾；manual 模式适合内容切换需要等待的场景。
