Tabs 标签页

在同一位置切换显示的几组内容。

转学第一天,我在天台遇见了那个抱着旧相机的少女。

import { Stack, Tabs, TabsContent, TabsList, TabsTrigger, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Tabs defaultValue="intro" className="w-full max-w-md">
      <TabsList label="作品信息">
        <TabsTrigger value="intro">简介</TabsTrigger>
        <TabsTrigger value="volumes">卷册</TabsTrigger>
        <TabsTrigger value="staff">制作</TabsTrigger>
      </TabsList>
      <TabsContent value="intro">
        <Stack gap="xs" className="pt-4">
          <Text tone="muted" size="sm">
            转学第一天,我在天台遇见了那个抱着旧相机的少女。
          </Text>
        </Stack>
      </TabsContent>
      <TabsContent value="volumes">
        <Stack gap="xs" className="pt-4">
          <Text tone="muted" size="sm">
            全 7 卷,第 8 卷预定于今年冬季发行。
          </Text>
        </Stack>
      </TabsContent>
      <TabsContent value="staff">
        <Stack gap="xs" className="pt-4">
          <Text tone="muted" size="sm">
            作者 支倉凍砂,插画 文倉十。
          </Text>
        </Stack>
      </TabsContent>
    </Tabs>
  )
}
tsx

用法

import { Tabs, TabsList, TabsTrigger, TabsContent } from '@hina-ui/react'
ts

组件由四部分构成:Tabs 持有当前选中项,TabsList 是页签所在的一行,TabsTrigger 是单个页签,TabsContent 是与之对应的内容。触发器与内容通过 value 一一对应。

正在读的 3 部作品。

import { Tabs, TabsContent, TabsList, TabsTrigger, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Tabs defaultValue="reading" className="w-full max-w-md">
      <TabsList label="书架分类">
        <TabsTrigger value="reading">在读</TabsTrigger>
        <TabsTrigger value="planned">想读</TabsTrigger>
        <TabsTrigger value="finished">读过</TabsTrigger>
      </TabsList>
      <TabsContent value="reading">
        <Text tone="muted" size="sm" className="block pt-4">
          正在读的 3 部作品。
        </Text>
      </TabsContent>
      <TabsContent value="planned">
        <Text tone="muted" size="sm" className="block pt-4">
          收藏待读的 12 部作品。
        </Text>
      </TabsContent>
      <TabsContent value="finished">
        <Text tone="muted" size="sm" className="block pt-4">
          已经读完的 48 部作品。
        </Text>
      </TabsContent>
    </Tabs>
  )
}
tsx

页签用于在同一位置切换几组并列的内容,各组之间没有先后顺序。若内容需要同时可见,应改用分节的标题;若是一次操作的若干步骤,应使用 Stepper。

示例

形态

underline 为默认形态,选中项由一条圆头线标示,适合与正文同宽的内容分组;soft 的选中项是一块浮起的滑块,适合工具栏与紧凑的切换。

选中项由一条圆头线标示。

选中项由一块浮起的滑块标示。

import { Stack, Tabs, TabsContent, TabsList, TabsTrigger, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Stack gap="lg" className="w-full max-w-md">
      <Tabs defaultValue="a" variant="underline">
        <TabsList label="下划线形态">
          <TabsTrigger value="a">underline</TabsTrigger>
          <TabsTrigger value="b">默认形态</TabsTrigger>
        </TabsList>
        <TabsContent value="a">
          <Text tone="muted" size="sm" className="block pt-3">
            选中项由一条圆头线标示。
          </Text>
        </TabsContent>
        <TabsContent value="b">
          <Text tone="muted" size="sm" className="block pt-3">
            适合与正文同宽的内容分组。
          </Text>
        </TabsContent>
      </Tabs>
      <Tabs defaultValue="a" variant="soft">
        <TabsList label="色块形态">
          <TabsTrigger value="a">soft</TabsTrigger>
          <TabsTrigger value="b">色块形态</TabsTrigger>
        </TabsList>
        <TabsContent value="a">
          <Text tone="muted" size="sm" className="block pt-3">
            选中项由一块浮起的滑块标示。
          </Text>
        </TabsContent>
        <TabsContent value="b">
          <Text tone="muted" size="sm" className="block pt-3">
            适合工具栏与紧凑的切换。
          </Text>
        </TabsContent>
      </Tabs>
    </Stack>
  )
}
tsx

标示选中项的那条线或滑块会随选中项平移与伸缩,不是瞬间跳转。

尺寸

size 改变的是这一行的疏密:sm 用于工具栏与密集界面,md 为默认,lg 用于页面顶部这类需要更多存在感的位置。

字号在三档中保持一致,页签属于界面 chrome,视觉分量由高度、内边距与选中标示给出。

sm

md

lg

import { Stack, Tabs, TabsContent, TabsList, TabsTrigger, Text } from '@hina-ui/react'

const sizes = ['sm', 'md', 'lg'] as const

export default function Demo() {
  return (
    <Stack gap="lg" className="w-full max-w-md">
      {sizes.map(size => (
        <Stack key={size} gap="xs">
          <Text tone="muted" size="sm">
            {size}
          </Text>
          <Tabs defaultValue="a" size={size}>
            <TabsList label={`${size} 档`}>
              <TabsTrigger value="a">简介</TabsTrigger>
              <TabsTrigger value="b">卷册</TabsTrigger>
            </TabsList>
            <TabsContent value="a" />
            <TabsContent value="b" />
          </Tabs>
        </Stack>
      ))}
    </Stack>
  )
}
tsx

纵向

将 orientation 设为 vertical,页签排成一列位于内容左侧,方向键随之改为上下切换。

用户名、邮箱与密码。

import { Tabs, TabsContent, TabsList, TabsTrigger, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Tabs defaultValue="account" orientation="vertical" className="w-full max-w-md">
      <TabsList label="设置分组">
        <TabsTrigger value="account">账号</TabsTrigger>
        <TabsTrigger value="reading">阅读</TabsTrigger>
        <TabsTrigger value="notice">通知</TabsTrigger>
      </TabsList>
      <TabsContent value="account">
        <Text tone="muted" size="sm">
          用户名、邮箱与密码。
        </Text>
      </TabsContent>
      <TabsContent value="reading">
        <Text tone="muted" size="sm">
          字号、行距与翻页方向。
        </Text>
      </TabsContent>
      <TabsContent value="notice">
        <Text tone="muted" size="sm">
          更新提醒与站内消息。
        </Text>
      </TabsContent>
    </Tabs>
  )
}
tsx

页签过多时

页签超出容器宽度时,该行本身可以横向滚动,并且不显示滚动条:滚动位置由两端的边缘阴影提示,鼠标可直接在该行上滚动滚轮,键盘则通过方向键在页签之间循环。

科幻题材的作品列表。

import { Tabs, TabsContent, TabsList, TabsTrigger, Text } from '@hina-ui/react'

const genres = ['科幻', '悬疑', '日常', '校园', '治愈', '奇幻', '推理', '恋爱', '历史', '战记']

export default function Demo() {
  return (
    <Tabs defaultValue="科幻" className="w-full max-w-sm">
      <TabsList label="题材">
        {genres.map(genre => (
          <TabsTrigger key={genre} value={genre}>
            {genre}
          </TabsTrigger>
        ))}
      </TabsList>
      {genres.map(genre => (
        <TabsContent key={genre} value={genre}>
          <Text tone="muted" size="sm" className="block pt-4">
            {genre}题材的作品列表。
          </Text>
        </TabsContent>
      ))}
    </Tabs>
  )
}
tsx

禁用

在 TabsTrigger 上设置 disabled,该页签不可选中,方向键也会跳过它。

所有人都能看到这份书单。

import { Tabs, TabsContent, TabsList, TabsTrigger, Text } from '@hina-ui/react'

export default function Demo() {
  return (
    <Tabs defaultValue="public" className="w-full max-w-md">
      <TabsList label="可见范围">
        <TabsTrigger value="public">公开</TabsTrigger>
        <TabsTrigger value="friends">仅关注者</TabsTrigger>
        <TabsTrigger value="private" disabled>
          私密(需要登录)
        </TabsTrigger>
      </TabsList>
      <TabsContent value="public">
        <Text tone="muted" size="sm" className="block pt-4">
          所有人都能看到这份书单。
        </Text>
      </TabsContent>
      <TabsContent value="friends">
        <Text tone="muted" size="sm" className="block pt-4">
          只有关注你的人能看到。
        </Text>
      </TabsContent>
      <TabsContent value="private">
        <Text tone="muted" size="sm" className="block pt-4">
          只有自己可见。
        </Text>
      </TabsContent>
    </Tabs>
  )
}
tsx

无障碍

  • 为 TabsList 提供 label,说明这一组页签切换的是什么。
  • 方向键在页签之间移动,Home 与 End 跳到首尾,选中项随焦点变化。
  • 内容区可聚焦,以便键盘用户从页签直接进入内容。

API

Tabs

属性
类型
默认值
说明
value
string
—
当前选中项,可受控
defaultValue
string
—
初始选中项
variant
'underline' | 'soft'
'underline'
形态
size
'sm' | 'md' | 'lg'
'md'
尺寸
orientation
'horizontal' | 'vertical'
'horizontal'
排列方向
className
string
—
追加至根元素的类名

TabsList

属性
类型
默认值
说明
label
string
—
这一组页签的名称
className
string
—
追加至该行的类名

TabsTrigger

属性
类型
默认值
说明
value
string
—
与内容对应的标识,必填
disabled
boolean
false
是否不可选中
className
string
—
追加至页签的类名

TabsContent

属性
类型
默认值
说明
value
string
—
与页签对应的标识,必填
className
string
—
追加至内容区的类名