如何引入
基本用法
带图标的
更多选项收入 More 展示
垂直的标签栏
滚动折叠
禁用
标签栏内容扩展
标签栏二次封装
动态更新
关闭
API 参考
Accessibility
设计变量
文案规范
FAQ
导航类 · Tabs
标签栏
当内容需要分组并在不同模块页面中展示,可使用 Tabs 标签栏目对不同的组/页之间进行切换
API 文档
设计文档
代码演示
如何引入
import { Tabs, TabPane } from '@douyinfe/semi-ui';
基本用法
标签栏支持三种样式的显示:线条式,按钮式,卡片式。默认选中第一项。
标签页支持两种传入方式,两者渲染流程上有所区别:
标签页支持两种传入方式,两者渲染流程上有所区别:
-
通过
tabList
传入标签页对象的数组,当使用tabList
时每次只渲染当前传入的节点 -
或使用
<TabPane>
逐项显式传入,使用<TabPane>
时默认会渲染所有面板,可以通过设置keepDOM={false}
只渲染当前面板,此时不会有动画效果。
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>