如何引入
基本用法
带图标的
更多选项收入 More 展示
垂直的标签栏
滚动折叠
禁用
标签栏内容扩展
标签栏二次封装
动态更新
关闭
API 参考
Accessibility
设计变量
文案规范
FAQ
导航类 · Tabs
标签栏
当内容需要分组并在不同模块页面中展示,可使用 Tabs 标签栏目对不同的组/页之间进行切换
API 文档
设计文档
代码演示
如何引入
import { Tabs, TabPane } from '@douyinfe/semi-ui';
基本用法
标签栏支持三种样式的显示:线条式,按钮式,卡片式。默认选中第一项。
标签页支持两种传入方式,两者渲染流程上有所区别:
标签页支持两种传入方式,两者渲染流程上有所区别:
-
通过
tabList
传入标签页对象的数组,当使用tabList
时每次只渲染当前传入的节点 -
或使用
<TabPane>
逐项显式传入,使用<TabPane>
时默认会渲染所有面板,可以通过设置keepDOM={false}
只渲染当前面板,此时不会有动画效果。
注意事项
1. tabList 与 TabPane Children 同时使用时,会优先渲染通过 tabList 传入的数据。不建议同时配置
2. 使用 TabPane Children 时, TabPane 必须为 Tabs 的直接子元素,否则 Tabs 将无法正确收集子组件如 itemKey 等相关属性
2. 使用 TabPane Children 时, TabPane 必须为 Tabs 的直接子元素,否则 Tabs 将无法正确收集子组件如 itemKey 等相关属性
import React from 'react';
import { Tabs, TabPane } from '@douyinfe/semi-ui';
() => (
<Tabs type="line">
<TabPane tab="文档" itemKey="1">
<h3>文档</h3>
<p style={{ lineHeight: 1.8 }}>
Semi Design 是由抖音前端团队与 UED
团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
Web 应用。
<p style={{ lineHeight: 1.8 }}>
区别于其他的设计系统而言,Semi Design 以用户中心、内容优先、设计人性化为设计理念,具有以下优势:
<p>Semi Design 以内容优先进行设计。</p>
<p>更容易地自定义主题。</p>
<p>适用国际化场景。</p>
<p>效率场景加入人性化关怀。</p>
</TabPane>
<TabPane tab="快速起步" itemKey="2">
<h3>快速起步</h3>
style={{
margin: '24px 0',
padding: '20px',
border: 'none',
whiteSpace: 'normal',
borderRadius: 'var(--semi-border-radius-medium)',
color: 'var(--semi-color-text-1)',
backgroundColor: 'var(--semi-color-fill-0)',
<code>yarn add @douyinfe/semi-ui</code>
</TabPane>
<TabPane tab="帮助" itemKey="3">
<h3>帮助</h3>
<p style={{ lineHeight: 1.8, color: 'var(--semi-color-text-0)', fontWeight: 600 }}>
Q:有新组件需求、或者现有组件feature不能满足业务需求?
<p style={{ lineHeight: 1.8, color: 'var(--semi-color-text-1)' }}>
右上角问题反馈,提交issue,label选择Feature Request / New Component Request 我们会高优处理这些需求。
<p style={{ lineHeight: 1.8, color: 'var(--semi-color-text-0)', fontWeight: 600 }}>
Q:对组件的使用有疑惑?
<p style={{ lineHeight: 1.8, color: 'var(--semi-color-text-1)' }}>
欢迎进我们的客服lark群进行咨询提问。
</TabPane>
</Tabs>
import React from 'react';
import { Tabs, TabPane } from '@douyinfe/semi-ui';
() => (
<Tabs type="button">
<TabPane tab="文档" itemKey="1">
</TabPane>
<TabPane tab="快速起步" itemKey="2">
</TabPane>
<TabPane tab="帮助" itemKey="3">
</TabPane>
</Tabs>
import React from 'react';
import { Tabs } from '@douyinfe/semi-ui';
class TabDemo extends React.Component {
constructor() {
super();
this.state = { key: '1' };
this.onTabClick = this.onTabClick.bind(this);
onTabClick(key, type) {
this.setState({ [type]: key });
render() {
// eslint-disable-next-line react/jsx-key
const contentList = [<div>文档</div>, <div>快速起步</div>, <div>帮助</div>];
const tabList = [
{ tab: '文档', itemKey: '1' },
{ tab: '快速起步', itemKey: '2' },
{ tab: '帮助', itemKey: '3' },
return (
type="card"
tabList={tabList}
onChange={key => {
this.onTabClick(key, 'key');
{contentList[this.state.key - 1]}
</Tabs>
带图标的
有图标的标签栏。
import React from 'react';
import { Tabs, TabPane } from '@douyinfe/semi-ui';
import { IconFile, IconGlobe, IconHelpCircle } from '@douyinfe/semi-icons';
() => (
<TabPane
tab={
<IconFile />
</span>
itemKey="1"
</TabPane>
<TabPane
tab={
<IconGlobe />
</span>
itemKey="2"
</TabPane>
<TabPane
tab={
<IconHelpCircle />
</span>
itemKey="3"
</TabPane>
</Tabs>
更多选项收入 More 展示
支持将多余 Tab 合并为 ”更多“ 下拉菜单,
more
传入数字即可,数字表示收入下拉菜单的 Tab 数量。
(>=v2.59.0)
import React from 'react';
import { Tabs, TabPane } from '@douyinfe/semi-ui';
function Demo() {
return (
<Tabs more={4} style={{ width: '60%', margin: '20px' }} type="card">
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(i => (
<TabPane tab={`Tab-${i}`} itemKey={`Tab-${i}`} key={i}>
Content of card tab {i}
</TabPane>
</Tabs>
也支持高级配置,向
more
传入对象,内可传入
-
count
: 表示收入下拉菜单的 Tab 数量 -
render
: 自定义 Trigger 的渲染函数,返回的 ReactNode 会被渲染为下拉菜单的 Trigger -
dropdownProps
: 传入 DropDown Props,会被透传到下拉菜单,如果需要自定义下拉菜单,使用 dropdownProps 中的 render 方法
import React from 'react';
import { Tabs, TabPane, Button } from '@douyinfe/semi-ui';
function Demo() {
return (
more={{
count: 4,
render: () => {
return <Button type='tertiary'>Click to show More</Button>;
dropdownProps: { trigger: 'click', position: 'bottomRight' },
style={{ width: '60%', margin: '20px' }}
type="card"
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(i => (
<TabPane tab={`Tab-${i}`} itemKey={`Tab-${i}`} key={i}>
Content of card tab {i}
</TabPane>
</Tabs>
垂直的标签栏
支持水平和垂直两种模式,
tabPosition='left|top'
import React from 'react';
import { Tabs, TabPane, RadioGroup, Radio } from '@douyinfe/semi-ui';
import { IconFile, IconGlobe, IconHelpCircle } from '@douyinfe/semi-icons';
class App extends React.Component {
constructor() {
super();
this.state = {
type: 'line',
onSelect(e) {
this.setState({
type: e.target.value,
render() {
return (
<RadioGroup
onChange={e => this.onSelect(e)}
value={this.state.type}
type="button"
style={{
display: 'flex',
width: 200,
justifyContent: 'center',
<Radio value={'line'}>Line</Radio>
<Radio value={'card'}>Card</Radio>
<Radio value={'button'}>Button</Radio>
</RadioGroup>
<Tabs tabPosition="left" type={this.state.type}>
<TabPane
tab={
<IconFile />
</span>
itemKey="1"
<div style={{ padding: '0 24px' }}>
<h3>文档</h3>
<p style={{ lineHeight: 1.8 }}>
Semi Design 是由抖音前端团队与 UED
团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的
Web 应用。
<p style={{ lineHeight: 1.8 }}>
区别于其他的设计系统而言,Semi Design
以用户中心、内容优先、设计人性化为设计理念,具有以下优势:
</TabPane>
<TabPane
tab={
<IconGlobe />
</span>
itemKey="2"
<div style={{ padding: '0 24px' }}>
<h3>快速起步</h3>
style={{
margin: '24px 0',
padding: '20px',
border: 'none',
whiteSpace: 'normal',
borderRadius: '6px',
color: 'var(--semi-color-text-1)',
backgroundColor: 'var(--semi-color-fill-0)',
<code>yarn add @douyinfe/semi-ui</code>
</TabPane>
<TabPane
tab={
<IconHelpCircle />
</span>
itemKey="3"
<div style={{ padding: '0 24px' }}>
<h3>帮助</h3>
<p style={{ lineHeight: 1.8, color: 'var(--semi-color-text-0)', fontWeight: 600 }}>
Q:有新组件需求、或者现有组件feature不能满足业务需求?
<p style={{ lineHeight: 1.8, color: 'var(--semi-color-text-1)' }}>
右上角问题反馈,提交issue,label选择Feature Request / New Component Request
我们会高优处理这些需求。
<p style={{ lineHeight: 1.8, color: 'var(--semi-color-text-0)', fontWeight: 600 }}>
Q:对组件的使用有疑惑?
<p style={{ lineHeight: 1.8, color: 'var(--semi-color-text-1)' }}>
欢迎进我们的客服lark群进行咨询提问。
</TabPane>
</Tabs>
滚动折叠
通过设置
collapsible
可以支持滚动折叠,目前只支持 horizontal 模式。
import React from 'react';
import { Tabs, TabPane } from '@douyinfe/semi-ui';
class App extends React.Component {
render() {
return (
<Tabs style={{ width: '60%', margin: '20px' }} type="card" collapsible>
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(i => (
<TabPane tab={`Tab-${i}`} itemKey={`Tab-${i}`} key={i}>
Content of card tab {i}
</TabPane>
</Tabs>
自定义滚动箭头渲染
通过 renderArrow 修改滚动折叠模式下,左右切换箭头的渲染,入参为溢出的 items 和 位置
import React from 'react';
import { Tabs, TabPane, Dropdown } from '@douyinfe/semi-ui';
() => {
const [activeKey, setActiveKey] = useState('Tab-0');
const renderArrow = (items, pos, handleArrowClick) => {
const style = {
width: 32,
height: 32,
margin: '0 12px',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
borderRadius: '100%',
background: 'rgba(var(--semi-grey-1), 1)',
color: 'var(--semi-color-text)',
cursor: 'pointer',
return (
<Dropdown
render={
<Dropdown.Menu>
{items.map(item => {
return (
<Dropdown.Item onClick={() => setActiveKey(item.itemKey)}>{item.itemKey}</Dropdown.Item>
</Dropdown.Menu>
{pos === 'start' ? (
<div style={style} onClick={handleArrowClick}>
) : (
<div style={style} onClick={handleArrowClick}>
</Dropdown>
return (
renderArrow={renderArrow}
style={{ width: '50%', margin: '20px' }}
activeKey={activeKey}
type="card"
collapsible
onChange={k => setActiveKey(k)}
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(i => (
<TabPane tab={`Tab-${i}`} itemKey={`Tab-${i}`} key={i}>
Content of card tab {i}
</TabPane>
</Tabs>
修改切换箭头的渲染位置
通过
arrowPosition
来修改溢出指示器的位置,可选
start
both
end
import React from 'react';
import { Tabs, TabPane } from '@douyinfe/semi-ui';
class App extends React.Component {
render() {
return (
<Tabs style={{ width: '60%', margin: '20px' }} type="card" collapsible arrowPosition={'start'}>
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(i => (
<TabPane tab={`Tab-${i}`} itemKey={`Tab-${i}`} key={i}>
Content of card tab {i}
</TabPane>
</Tabs>
<Tabs style={{ width: '60%', margin: '20px' }} type="card" collapsible arrowPosition={'both'}>
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(i => (
<TabPane tab={`Tab-${i}`} itemKey={`Tab-${i}`} key={i}>
Content of card tab {i}
</TabPane>
</Tabs>
<Tabs style={{ width: '60%', margin: '20px' }} type="card" collapsible arrowPosition={'end'}>
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(i => (
<TabPane tab={`Tab-${i}`} itemKey={`Tab-${i}`} key={i}>
Content of card tab {i}
</TabPane>
</Tabs>
禁用
禁用标签栏中的某一个标签页。
import React from 'react';
import { Tabs, TabPane } from '@douyinfe/semi-ui';
class App extends React.Component {
render() {
return (
<Tabs defaultActiveKey="1">
<TabPane tab="文档" itemKey="1">
</TabPane>
<TabPane tab="快速起步" itemKey="2" disabled>
</TabPane>
<TabPane tab="帮助" itemKey="3">
</TabPane>
</Tabs>
标签栏内容扩展
传入
tabBarExtraContent
属性可以在标签栏右侧添加附加操作。
import React from 'react';
import { Tabs, TabPane, Button } from '@douyinfe/semi-ui';
() => (
defaultActiveKey="1"
tabBarExtraContent={
<Button
onClick={() => {
alert('you have clicked me!');
Extra Action
</Button>
<TabPane tab="文档" itemKey="1">
</TabPane>
<TabPane tab="快速起步" itemKey="2">
</TabPane>
<TabPane tab="帮助" itemKey="3">
</TabPane>
</Tabs>
标签栏二次封装
传入
renderTabBar
函数可对标签栏进行二次封装。
import React from 'react';
import { Tabs, TabPane } from '@douyinfe/semi-ui';
() => (
defaultActiveKey="1"
renderTabBar={(tabBarProps, DefaultTabBar) => {
return (
<div className="tab-bar-box">
这是二次封装的Tab Bar,当前ActiveKey:{tabBarProps.activeKey}
<DefaultTabBar {...tabBarProps} />
<TabPane tab="文档" itemKey="1">
</TabPane>
<TabPane tab="快速起步" itemKey="2">
</TabPane>
<TabPane tab="帮助" itemKey="3">
</TabPane>
</Tabs>
动态更新
通过绑定事件,可以使标签栏动态更新。
import React from 'react';
import { Tabs, TabPane, ButtonGroup, Button } from '@douyinfe/semi-ui';
class App extends React.Component {
constructor(props) {
super(props);
this.newTabIndex = 0;
const panes = [
{ title: 'Tab 1', content: 'Content of Tab Pane 1', itemKey: '1' },
{ title: 'Tab 2', content: 'Content of Tab Pane 2', itemKey: '2' },
this.state = {
panes,
activeKey: panes[0].itemKey,
add() {
const { panes } = this.state;
const index = this.newTabIndex++;
panes.push({ title: `New Tab ${index}`, content: 'New Tab Pane', itemKey: `newTab${index}` });
this.setState({ panes, activeKey: `newTab${index}` });
remove() {
const { panes } = this.state;
if (panes.length > 1) {
panes.pop();
this.setState({ panes, activeKey: panes[panes.length - 1].itemKey });
handleChange(activeKey) {
this.setState({ activeKey });
render() {
const { panes, activeKey } = this.state;
return (
defaultActiveKey="1"
activeKey={activeKey}
onChange={this.handleChange.bind(this)}
tabBarExtraContent={
<ButtonGroup>
<Button onClick={() => this.add()}>新增</Button>
<Button onClick={() => this.remove()}>删除</Button>
</ButtonGroup>
{panes.map(pane => (
<TabPane tab={pane.title} itemKey={pane.itemKey} key={pane.itemKey}>
{pane.content}
</TabPane>
</Tabs>
关闭
关闭标签栏中的某一个标签页。
只有卡片样式的页签支持关闭选项。使用
只有卡片样式的页签支持关闭选项。使用
closable={true}
来开启。
import React from 'react';
import { Tabs, TabPane } from '@douyinfe/semi-ui';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
tabList: [
{ tab: '文档', itemKey: '1', text: '文档', closable: true },
{ tab: '快速起步', itemKey: '2', text: '快速起步', closable: true },
{ tab: '帮助', itemKey: '3', text: '帮助' },
close(key) {
const newTabList = [...this.state.tabList];
const closeIndex = newTabList.findIndex(t => t.itemKey === key);
newTabList.splice(closeIndex, 1);
this.setState({ tabList: newTabList });
render() {
return (
<Tabs type="card" defaultActiveKey="1" onTabClose={this.close.bind(this)}>
{this.state.tabList.map(t => (
<TabPane closable={t.closable} tab={t.tab} itemKey={t.itemKey} key={t.itemKey}>
{t.text}
</TabPane>