标签页
通过原生 Tabs 与 Tab 在相关内容面板之间切换。
本指南覆盖默认 Emotion 环境的 Material UI Core;扩展包与额外示例按清单单独标注。
使用场景与业务边界
Core 需要宿主提供面板语义;Lab TabContext/TabList/TabPanel 不在本轮内。隐藏但保留挂载的面板仍可能运行副作用。
原生组成与范围
Tabs, Tab, TabScrollButton
保持 Material UI 原生组合与类型,不替换为 JGuang/Base UI/Radix 同名 API。示例条目不是额外组件。
未纳入的集成: TabContext (@mui/lab), TabList (@mui/lab), TabPanel (@mui/lab). 不宣称已在默认 Emotion 环境验证。
原生安装与初始化
npm install @mui/material@9.4.0 @emotion/react@11.14.0 @emotion/styled@11.14.1
采用原生 npm 包与 Emotion,不提供虚构的 JGuang UI Registry 地址。将示例放在原生 ThemeProvider 内,按项目选择 CssBaseline 或 ScopedCssBaseline。先检查 React、现有 Provider、锁文件与 SSR 配置;不要覆盖用户文件或忽略 peer 冲突。本批实际验收 React 19.2.8;React 18 及以下须匹配 react-is。完整初始化规则见随附的双语 setup 文档。
关键原生参数
仅解释本指南选出的关键参数,不是平铺的通用 API。原生继承来源、slot 结构、可空值与泛型仍按固定源码保留。
| 所属组件.属性 | 用途说明 | 声明来源 |
|---|---|---|
Tabs.value | 受控原生值,其单值/数组/可空类型取决于所属组件。 | Tabs |
Tabs.onChange | 所属控件的原生回调,保留其准确事件/数值/可空签名。 | Tabs |
Tabs.variant | 所属组件的原生视觉枚举,不可替换为通用 variant 属性。 | Tabs |
Tabs.selectionFollowsFocus | 仅在面板加载足够即时的情况下,让 Tabs 随键盘焦点激活。 | Tabs |
Tab.disabled | 原生禁用交互状态,不是权限校验。 | Tab |
可运行原生示例
下列机器键只选择示例入口,不会作为通用 variant 属性传入每个组件。原生示例 JSX 与数据保持上游原文;JGuang 编写的验收示例明确标注。
- 基础介绍 ·
BasicTabs· 上游原生示例 - 使用标准 Core API ·
KeepMountedStandardTabs· 上游原生示例 - 标签换行 ·
TabsWrappedLabel· 上游原生示例 - 标签页颜色 ·
ColorTabs· 上游原生示例 - 禁用标签页 ·
DisabledTabs· 上游原生示例 - 占满宽度 ·
FullWidthTabs· 上游原生示例 - 居中 ·
CenteredTabs· 上游原生示例 - 自动显示滚动按钮 ·
ScrollableTabsButtonAuto· 上游原生示例 - 始终显示滚动按钮 ·
ScrollableTabsButtonForce· 上游原生示例 - 始终显示滚动按钮 ·
ScrollableTabsButtonVisible· 上游原生示例 - 隐藏滚动按钮 ·
ScrollableTabsButtonPrevent· 上游原生示例 - 定制样式 ·
CustomizedTabs· 上游原生示例 - 纵向标签页 ·
VerticalTabs· 上游原生示例 - 导航标签页 ·
NavTabs· 上游原生示例 - 图标标签页 ·
IconTabs· 上游原生示例 - 图标标签页 ·
IconLabelTabs· 上游原生示例 - 图标位置 ·
IconPositionTabs· 上游原生示例 - 焦点跟随选择的键盘标签页 ·
AccessibleTabs1· 上游原生示例 - 手动确认选择的键盘标签页 ·
AccessibleTabs2· 上游原生示例
尚未支持的额外示例
这些条目仍保留在上游清单中,不静默跳过,也不展示为已完成预览。需要补充依赖/框架验收后再纳入可运行列表。
- 实验性 API,Lab ·
LabTabs:@mui/lab/TabContext,@mui/lab/TabList,@mui/lab/TabPanel - Lab API 扩展 ·
KeepMountedLabTabs:@mui/lab/TabContext,@mui/lab/TabList,@mui/lab/TabPanel
真实使用示例
固定版本的未修改原生示例;复制时同时保留所需的局部辅助文件。
import * as React from 'react';
import Tabs from '@mui/material/Tabs';
import Tab from '@mui/material/Tab';
import Box from '@mui/material/Box';
interface TabPanelProps {
children?: React.ReactNode;
index: number;
value: number;
}
function CustomTabPanel(props: TabPanelProps) {
const { children, value, index, ...other } = props;
return (
<div
role="tabpanel"
hidden={value !== index}
tabIndex={0}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{value === index && <Box sx={{ p: 3 }}>{children}</Box>}
</div>
);
}
function a11yProps(index: number) {
return {
id: `simple-tab-${index}`,
'aria-controls': `simple-tabpanel-${index}`,
};
}
export default function BasicTabs() {
const [value, setValue] = React.useState(0);
const handleChange = (event: React.SyntheticEvent, newValue: number) => {
setValue(newValue);
};
return (
<Box sx={{ width: '100%' }}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<Tabs value={value} onChange={handleChange} aria-label="basic tabs example">
<Tab label="Item One" {...a11yProps(0)} />
<Tab label="Item Two" {...a11yProps(1)} />
<Tab label="Item Three" {...a11yProps(2)} />
</Tabs>
</Box>
<CustomTabPanel value={value} index={0}>
Item One
</CustomTabPanel>
<CustomTabPanel value={value} index={1}>
Item Two
</CustomTabPanel>
<CustomTabPanel value={value} index={2}>
Item Three
</CustomTabPanel>
</Box>
);
}
示例依赖边界
react, @mui/material/Tabs, @mui/material/Tab, @mui/material/Box, @mui/material/TextField, @mui/material/styles, @mui/material/AppBar, @mui/material/Typography, @mui/icons-material/Phone, @mui/icons-material/Favorite, @mui/icons-material/PersonPin, @mui/icons-material/PhoneMissed
直接导入 Icons/System/Utils 的示例需要匹配 9.4.0 包。局部数据与辅助文件属于示例闭包,不是额外组件。远程图片和模拟操作不提供后端。
固定上游 API 元数据参考
以下表格保留上游元数据,不是重新推断的通用类型体系。条件泛型、继承属性与回调细节以以下源码声明为准。主题默认配置可能覆盖元数据默认值。
Tabs
import Tabs from '@mui/material/Tabs';
import { Tabs } from '@mui/material';
| 属性 | 必需 | 上游元数据类型/约束 | 元数据默认值 |
|---|---|---|---|
action | 否 | ref | — |
allowScrollButtonsMobile | 否 | bool | false |
aria-label | 否 | string | — |
aria-labelledby | 否 | string | — |
centered | 否 | bool | false |
children | 否 | node | — |
classes | 否 | object | — |
component | 否 | elementType | — |
indicatorColor | 否 | 'primary' | 'secondary' | string | 'primary' |
onChange | 否 | func | — |
orientation | 否 | 'horizontal' | 'vertical' | 'horizontal' |
scrollButtons | 否 | 'auto' | false | true | 'auto' |
selectionFollowsFocus | 否 | bool | — |
slotProps | 否 | { endScrollButtonIcon?: func | object, indicator?: func | object, list?: func | object, root?: func | object, scrollbar?: func | object, scrollButtons?: func | object, scroller?: func | object, startScrollButtonIcon?: func | object } | {} |
slots | 否 | { endScrollButtonIcon?: elementType, indicator?: elementType, list?: elementType, root?: elementType, scrollbar?: elementType, scrollButtons?: elementType, scroller?: elementType, startScrollButtonIcon?: elementType } | {} |
sx | 否 | Array<func | object | bool> | func | object | — |
textColor | 否 | 'inherit' | 'primary' | 'secondary' | 'primary' |
value | 否 | any | — |
variant | 否 | 'fullWidth' | 'scrollable' | 'standard' | 'standard' |
visibleScrollbar | 否 | bool | false |
Tab
import Tab from '@mui/material/Tab';
import { Tab } from '@mui/material';
原生继承: ButtonBase. 父级与 DOM 属性未被伪造为本组件新属性。
| 属性 | 必需 | 上游元数据类型/约束 | 元数据默认值 |
|---|---|---|---|
children | 否 | unsupportedProp | — |
classes | 否 | object | — |
disabled | 否 | bool | false |
disableFocusRipple | 否 | bool | false |
disableRipple | 否 | bool | false |
icon | 否 | element | string | — |
iconPosition | 否 | 'bottom' | 'end' | 'start' | 'top' | 'top' |
label | 否 | node | — |
sx | 否 | Array<func | object | bool> | func | object | — |
value | 否 | any | — |
wrapped | 否 | bool | false |
TabScrollButton
import TabScrollButton from '@mui/material/TabScrollButton';
import { TabScrollButton } from '@mui/material';
| 属性 | 必需 | 上游元数据类型/约束 | 元数据默认值 |
|---|---|---|---|
direction | 是 | 'left' | 'right' | — |
orientation | 是 | 'horizontal' | 'vertical' | — |
children | 否 | node | — |
classes | 否 | object | — |
disabled | 否 | bool | false |
slotProps | 否 | { endScrollButtonIcon?: func | object, startScrollButtonIcon?: func | object } | {} |
slots | 否 | { EndScrollButtonIcon?: elementType, StartScrollButtonIcon?: elementType } | {} |
sx | 否 | Array<func | object | bool> | func | object | — |
原生源码声明
声明与 import 从固定源码提取,不平铺联合类型或外部继承。英文注释/类型属于原始源码参考,不代表上游正文已全文翻译。共享类型仍位于原生包中。
vendor/src/Tabs/Tabs.d.ts
import * as React from 'react';
import { SxProps } from '@mui/system';
import { OverridableStringUnion } from '@mui/types';
import { CreateSlotsAndSlotProps, SlotProps } from '../utils/types';
import { Theme } from '../styles';
import TabScrollButton from '../TabScrollButton';
import { OverridableComponent, OverrideProps } from '../OverridableComponent';
import { TabsClasses } from './tabsClasses';
import SvgIcon from '../SvgIcon';
export interface TabsPropsIndicatorColorOverrides {}
export interface TabsPropsVariantOverrides {}
export interface TabsRootSlotPropsOverrides {}
export interface TabsScrollerSlotPropsOverrides {}
export interface TabsListSlotPropsOverrides {}
export interface TabsScrollbarSlotPropsOverrides {}
export interface TabsIndicatorSlotPropsOverrides {}
export interface TabsScrollButtonsSlotPropsOverrides {}
export interface TabsStartScrollButtonIconSlotPropsOverrides {}
export interface TabsEndScrollButtonIconSlotPropsOverrides {}
export interface TabsSlots {
/**
* The component used for the popper.
* @default div
*/
root: React.ElementType;
/**
* The component used for the scroller.
* @default div
*/
scroller: React.ElementType;
/**
* The component used for the flex container.
* @default div
*/
list: React.ElementType;
/**
* The component used for the scroller.
* @default ScrollbarSize
*/
scrollbar: React.ElementType;
/**
* The component used for the tab indicator.
* @default span
*/
indicator: React.ElementType;
/**
* The component used for the scroll button.
* @default TabScrollButton
*/
scrollButtons: React.ElementType;
/**
* The component used for the start scroll button icon.
* @default KeyboardArrowLeft
*/
startScrollButtonIcon: React.ElementType;
/**
* The component used for the end scroll button icon.
* @default KeyboardArrowRight
*/
endScrollButtonIcon: React.ElementType;
}
export type TabsSlotsAndSlotProps = CreateSlotsAndSlotProps<
TabsSlots,
{
/**
* Props forwarded to the root slot.
* By default, the available props are based on the div element.
*/
root: SlotProps<'div', TabsRootSlotPropsOverrides, TabsOwnerState>;
/**
* Props forwarded to the scroller slot.
* By default, the available props are based on the div element.
*/
scroller: SlotProps<'div', TabsScrollerSlotPropsOverrides, TabsOwnerState>;
/**
* Props forwarded to the list slot.
* By default, the available props are based on the div element.
*/
list: SlotProps<'div', TabsListSlotPropsOverrides, TabsOwnerState>;
/**
* Props forwarded to the scrollbar slot.
* By default, the available props are based on the div element.
*/
scrollbar: SlotProps<
'div',
{
onChange?: ((scrollbarWidth: undefined | number) => void) | undefined;
} & TabsScrollbarSlotPropsOverrides,
TabsOwnerState
>;
/**
* Props forwarded to the indicator slot.
* By default, the available props are based on the span element.
*/
indicator: SlotProps<'span', TabsIndicatorSlotPropsOverrides, TabsOwnerState>;
/**
* Props forwarded to the scrollButtons slot.
* By default, the available props are based on the [TabScrollButton](https://mui.com/material-ui/api/tab-scroll-button/#props) component.
*/
scrollButtons: SlotProps<
typeof TabScrollButton,
TabsScrollButtonsSlotPropsOverrides,
TabsOwnerState
>;
/**
* Props forwarded to the startScrollButtonIcon slot.
* By default, the available props are based on the [SvgIcon](https://mui.com/material-ui/api/svg-icon/#props) component.
*/
startScrollButtonIcon: SlotProps<
typeof SvgIcon,
TabsStartScrollButtonIconSlotPropsOverrides,
TabsOwnerState
>;
/**
* Props forwarded to the endScrollButtonIcon slot.
* By default, the available props are based on the [SvgIcon](https://mui.com/material-ui/api/svg-icon/#props) component.
*/
endScrollButtonIcon: SlotProps<
typeof SvgIcon,
TabsEndScrollButtonIconSlotPropsOverrides,
TabsOwnerState
>;
}
>;
export interface TabsOwnerState extends Omit<TabsProps, 'slots' | 'slotProps'> {
vertical: boolean;
fixed: boolean;
hideScrollbar: boolean;
scrollableX: boolean;
scrollableY: boolean;
centered: boolean;
scrollButtonsHideMobile: boolean;
}
export interface TabsOwnProps extends TabsSlotsAndSlotProps {
/**
* Callback fired when the component mounts.
* This is useful when you want to trigger an action programmatically.
* It supports two actions: `updateIndicator()` and `updateScrollButtons()`
*
* @param {object} actions This object contains all possible actions
* that can be triggered programmatically.
*/
action?: React.Ref<TabsActions> | undefined;
/**
* If `true`, the scroll buttons aren't forced hidden on mobile.
* By default the scroll buttons are hidden on mobile and takes precedence over `scrollButtons`.
* @default false
*/
allowScrollButtonsMobile?: boolean | undefined;
/**
* The label for the Tabs as a string.
*/
'aria-label'?: string | undefined;
/**
* An id or list of ids separated by a space that label the Tabs.
*/
'aria-labelledby'?: string | undefined;
/**
* If `true`, the tabs are centered.
* This prop is intended for large views.
* @default false
*/
centered?: boolean | undefined;
/**
* The content of the component.
*/
children?: React.ReactNode;
/**
* Override or extend the styles applied to the component.
*/
classes?: Partial<TabsClasses> | undefined;
/**
* Determines the color of the indicator.
* @default 'primary'
*/
indicatorColor?:
OverridableStringUnion<'secondary' | 'primary', TabsPropsIndicatorColorOverrides> | undefined;
/**
* Callback fired when the value changes.
*
* @param {React.SyntheticEvent} event The event source of the callback. **Warning**: This is a generic event not a change event.
* @param {any} value We default to the index of the child (number)
*/
onChange?: ((event: React.SyntheticEvent, value: any) => void) | undefined;
/**
* The component orientation (layout flow direction).
* @default 'horizontal'
*/
orientation?: 'horizontal' | 'vertical' | undefined;
/**
* Determine behavior of scroll buttons when tabs are set to scroll:
*
* - `auto` will only present them when not all the items are visible.
* - `true` will always present them.
* - `false` will never present them.
*
* By default the scroll buttons are hidden on mobile.
* This behavior can be disabled with `allowScrollButtonsMobile`.
* @default 'auto'
*/
scrollButtons?: 'auto' | true | false | undefined;
/**
* If `true` the selected tab changes on focus. Otherwise it only
* changes on activation.
*/
selectionFollowsFocus?: boolean | undefined;
/**
* Determines the color of the `Tab`.
* @default 'primary'
*/
textColor?: 'secondary' | 'primary' | 'inherit' | undefined;
/**
* The value of the currently selected `Tab`.
* If you don't want any selected `Tab`, you can set this prop to `false`.
*/
value?: any;
/**
* Determines additional display behavior of the tabs:
*
* - `scrollable` will invoke scrolling properties and allow for horizontally
* scrolling (or swiping) of the tab bar.
* - `fullWidth` will make the tabs grow to use all the available space,
* which should be used for small views, like on mobile.
* - `standard` will render the default state.
* @default 'standard'
*/
variant?:
| OverridableStringUnion<'standard' | 'scrollable' | 'fullWidth', TabsPropsVariantOverrides>
| undefined;
/**
* If `true`, the scrollbar is visible. It can be useful when displaying
* a long vertical list of tabs.
* @default false
*/
visibleScrollbar?: boolean | undefined;
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps<Theme> | undefined;
}
export interface TabsTypeMap<
AdditionalProps = {},
RootComponent extends React.ElementType = 'div',
> {
props: AdditionalProps & TabsOwnProps;
defaultComponent: RootComponent;
}
declare const Tabs: OverridableComponent<TabsTypeMap>;
export interface TabsActions {
updateIndicator(): void;
updateScrollButtons(): void;
}
export type TabsProps<
RootComponent extends React.ElementType = TabsTypeMap['defaultComponent'],
AdditionalProps = {},
> = OverrideProps<TabsTypeMap<AdditionalProps, RootComponent>, RootComponent> & {
component?: React.ElementType | undefined;
};
vendor/src/Tab/Tab.d.ts
import * as React from 'react';
import { SxProps } from '@mui/system';
import { Theme } from '../styles';
import { ExtendButtonBase, ExtendButtonBaseTypeMap } from '../ButtonBase';
import { OverrideProps } from '../OverridableComponent';
import { TabClasses } from './tabClasses';
export interface TabOwnProps {
/**
* This prop isn't supported.
* Use the `component` prop if you need to change the children structure.
*/
children?: null | undefined;
/**
* Override or extend the styles applied to the component.
*/
classes?: Partial<TabClasses> | undefined;
/**
* If `true`, the component is disabled.
* @default false
*/
disabled?: boolean | undefined;
/**
* If `true`, the keyboard focus ripple is disabled.
* @default false
*/
disableFocusRipple?: boolean | undefined;
/**
* The icon to display.
*/
icon?: string | React.ReactElement<unknown> | undefined;
/**
* The position of the icon relative to the label.
* @default 'top'
*/
iconPosition?: 'top' | 'bottom' | 'start' | 'end' | undefined;
/**
* The label element.
*/
label?: React.ReactNode;
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps<Theme> | undefined;
/**
* You can provide your own value. Otherwise, we fallback to the child position index.
*/
value?: any;
/**
* Tab labels appear in a single row.
* They can use a second line if needed.
* @default false
*/
wrapped?: boolean | undefined;
}
export type TabTypeMap<
AdditionalProps = {},
RootComponent extends React.ElementType = 'div',
> = ExtendButtonBaseTypeMap<{
props: AdditionalProps & TabOwnProps;
defaultComponent: RootComponent;
}>;
declare const Tab: ExtendButtonBase<TabTypeMap>;
export type TabProps<
RootComponent extends React.ElementType = TabTypeMap['defaultComponent'],
AdditionalProps = {},
> = OverrideProps<TabTypeMap<AdditionalProps, RootComponent>, RootComponent> & {
component?: React.ElementType | undefined;
};
vendor/src/TabScrollButton/TabScrollButton.d.ts
import * as React from 'react';
import { SxProps } from '@mui/system';
import { SlotComponentProps } from '../utils/types';
import { ButtonBaseProps } from '../ButtonBase';
import { Theme } from '../styles';
import SvgIcon from '../SvgIcon';
import { TabScrollButtonClasses } from './tabScrollButtonClasses';
export interface TabScrollButtonStartIconSlotPropsOverrides {}
export interface TabScrollButtonEndIconSlotPropsOverrides {}
export interface TabScrollButtonOwnerState extends TabScrollButtonProps {
isRtl: boolean;
}
export interface TabScrollButtonProps extends Omit<ButtonBaseProps, 'nativeButton'> {
/**
* The content of the component.
*/
children?: React.ReactNode;
/**
* Override or extend the styles applied to the component.
*/
classes?: Partial<TabScrollButtonClasses> | undefined;
/**
* The components used for each slot inside.
* @default {}
*/
slots?:
| {
StartScrollButtonIcon?: React.ElementType | undefined;
EndScrollButtonIcon?: React.ElementType | undefined;
}
| undefined;
/**
* The extra props for the slot components.
* You can override the existing props or add new ones.
* @default {}
*/
slotProps?:
| {
startScrollButtonIcon?:
| SlotComponentProps<
typeof SvgIcon,
TabScrollButtonStartIconSlotPropsOverrides,
TabScrollButtonOwnerState
>
| undefined;
endScrollButtonIcon?:
| SlotComponentProps<
typeof SvgIcon,
TabScrollButtonEndIconSlotPropsOverrides,
TabScrollButtonOwnerState
>
| undefined;
}
| undefined;
/**
* The direction the button should indicate.
*/
direction: 'left' | 'right';
/**
* If `true`, the component is disabled.
* @default false
*/
disabled?: boolean | undefined;
/**
* The component orientation (layout flow direction).
*/
orientation: 'horizontal' | 'vertical';
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps<Theme> | undefined;
}
export default function TabScrollButton(props: TabScrollButtonProps): React.JSX.Element;
安装后验收
执行严格类型检查、生产构建和实际交互。检查键盘标签/焦点、原生支持的禁用/错误/只读语义、深浅色、窄屏和减少动画。按真实宿主数据检查回调,不把复制提示词当作安装完成。初始化工具还需检查服务端 HTML 与无告警水合。
来源与许可
https://github.com/mui/material-ui/tree/809a7717b4c050ba3f69b75300689f07c050a16e
MIT · @mui/material@9.4.0. 保留上游原始内容与许可证。上游完整原文保留于 vendor/docs,不标为全文中文化。