选项卡
查看源代码同一页面上相关面板之间切换的组件。
演示
import { SpriteIcon } from "~/components/sprite-icon";
import { Tabs, TabsList, TabsTab, TabsIndicator, TabsPanel } from "@resolid/react-ui";
export default function App() {
return (
<Tabs defaultValue={"auto"} className={"border-bd-normal w-auto rounded-md border"}>
<TabsList className={"border-bd-normal gap-1 border-b p-1"}>
<TabsIndicator className={"bg-bg-primary-emphasis w-(--wv) -bottom-px h-0.5"} />
<TabsTab value={"auto"} className={"rounded-md px-3"}>
Auto
</TabsTab>
<TabsTab value={"light"} className={"rounded-md px-3"}>
Light
</TabsTab>
<TabsTab value={"dark"} className={"rounded-md px-3"}>
Dark
</TabsTab>
</TabsList>
<TabsPanel value={"auto"} className={"text-bg-muted flex items-center justify-center p-16"}>
<SpriteIcon name={"auto"} size={"3rem"} />
</TabsPanel>
<TabsPanel value={"light"} className={"text-bg-muted flex items-center justify-center p-16"}>
<SpriteIcon name={"sun"} size={"3rem"} />
</TabsPanel>
<TabsPanel value={"dark"} className={"text-bg-muted flex items-center justify-center p-16"}>
<SpriteIcon name={"moon"} size={"3rem"} />
</TabsPanel>
</Tabs>
);
}
使用
import { Tabs, TabsList, TabsTab, TabsIndicator, TabsPanel } from "@resolid/react-ui";
Tabs
: 将选项卡和相应面板分组。TabsList
: 分组单个选项卡按钮。TabsTab
: 单个交互式选项卡按钮,可切换相应的面板。TabsIndicator
: 突出显示当前活动选项卡的指示器。TabsPanel
: 当“对应”选项卡处于活动状态时显示的面板。
选项卡默认只有必需的样式,你可以通过 Tabs
、TabsList
、TabsTab
和 TabsPanel
的 className
自定义。
<Tabs>
<TabsList>
<TabsTab />
</TabsList>
<TabsPanel />
</Tabs>
特点
- 遵循 WAI ARIA Tabs 设计模式。
- 完整的键盘导航。
- 支持水平/垂直方向。
- 可以是受控的,也可以是不受控的。
举例
垂直
import { SpriteIcon } from "~/components/sprite-icon";
import { Tabs, TabsList, TabsIndicator, TabsTab, TabsPanel } from "@resolid/react-ui";
export default function App() {
return (
<Tabs
className={"border-bd-normal w-auto rounded-md border"}
orientation={"vertical"}
defaultValue={"light"}
>
<TabsList className={"border-bd-normal border-e p-1"}>
<TabsIndicator className={"bg-bg-subtle -z-1 w-(--wv) h-(--hv) rounded-md"} />
<TabsTab value={"auto"} className={"rounded-md px-3"}>
Auto
</TabsTab>
<TabsTab value={"light"} className={"rounded-md px-3"}>
Light
</TabsTab>
<TabsTab value={"dark"} className={"rounded-md px-3"}>
Dark
</TabsTab>
</TabsList>
<TabsPanel value={"auto"} className={"text-bg-muted flex items-center justify-center p-16"}>
<SpriteIcon name={"auto"} size={"3rem"} />
</TabsPanel>
<TabsPanel value={"light"} className={"text-bg-muted flex items-center justify-center p-16"}>
<SpriteIcon name={"sun"} size={"3rem"} />
</TabsPanel>
<TabsPanel value={"dark"} className={"text-bg-muted flex items-center justify-center p-16"}>
<SpriteIcon name={"moon"} size={"3rem"} />
</TabsPanel>
</Tabs>
);
}
禁用
import { SpriteIcon } from "~/components/sprite-icon";
import { Tabs, TabsList, TabsTab, TabsIndicator, TabsPanel } from "@resolid/react-ui";
export default function App() {
return (
<Tabs className={"border-bd-normal w-auto rounded-md border"} defaultValue={"auto"}>
<TabsList className={"border-bd-normal border-b p-1"}>
<TabsIndicator className={"bg-bg-primary-emphasis w-(--wv) -bottom-px h-0.5"} />
<TabsTab value={"auto"} className={"rounded-md px-3"}>
Auto
</TabsTab>
<TabsTab value={"light"} disabled className={"rounded-md px-3"}>
Light
</TabsTab>
<TabsTab value={"dark"} className={"rounded-md px-3"}>
Dark
</TabsTab>
</TabsList>
<TabsPanel value={"auto"} className={"text-bg-muted flex items-center justify-center p-16"}>
<SpriteIcon name={"auto"} size={"3rem"} />
</TabsPanel>
<TabsPanel value={"light"} className={"text-bg-muted flex items-center justify-center p-16"}>
<SpriteIcon name={"sun"} size={"3rem"} />
</TabsPanel>
<TabsPanel value={"dark"} className={"text-bg-muted flex items-center justify-center p-16"}>
<SpriteIcon name={"moon"} size={"3rem"} />
</TabsPanel>
</Tabs>
);
}
动态
这是如何动态添加和删除选项卡的示例。
import { useState } from "react";
import {
Tabs,
TabsList,
TabsTab,
TabsIndicator,
TabsPanel,
Button,
CloseButton,
} from "@resolid/react-ui";
const items = [
{ id: "1", title: "Tab", content: "Tab-1" },
{ id: "2", title: "Tab", content: "Tab-2" },
{ id: "3", title: "Tab", content: "Tab-3" },
];
export default function App() {
const [tabs, setTabs] = useState(items);
const [selected, setSelected] = useState(items[0].id);
const addTab = () => {
const uid = Math.random().toString(36).substring(2, 15);
setTabs([
...tabs,
{
id: uid,
title: `Tab`,
content: `Tab-${uid}`,
},
]);
setSelected(uid);
};
const removeTab = (id) => {
if (tabs.length > 1) {
const tabIndex = tabs.findIndex((tab) => tab.id === id);
const newTabs = [...tabs.slice(0, tabIndex), ...tabs.slice(tabIndex + 1)];
setTabs(newTabs);
if (id === selected) {
setSelected(newTabs[Math.max(tabIndex - 1, 0)].id);
}
}
};
return (
<Tabs
value={selected}
onChange={setSelected}
className={"border-bd-normal min-w-90 w-auto rounded-md border"}
>
<TabsList className={"border-bd-normal border-b p-1"}>
<TabsIndicator className={"bg-bg-primary-emphasis w-(--wv) -bottom-px h-0.5"} />
{tabs.map((tab) => {
return (
<TabsTab
render={(props) => <div {...props} />}
key={tab.id}
value={tab.id}
className={"inline-flex select-none items-center rounded-md pe-1 ps-3"}
>
{tab.title}
<CloseButton
size={"1em"}
className={"ms-2"}
onClick={(e) => {
e.stopPropagation();
removeTab(tab.id);
}}
/>
</TabsTab>
);
})}
<Button
variant={"ghost"}
color={"neutral"}
className={"ms-1.5 px-1.5 py-0.5"}
noPadding
onClick={addTab}
>
Add Tab
</Button>
</TabsList>
{tabs.map((tab) => {
return (
<TabsPanel key={tab.id} value={tab.id} className={"p-4"}>
{tab.content}
</TabsPanel>
);
})}
</Tabs>
);
}
属性
Tabs
属性 | 类型 | 默认值 | 必须 | |
---|---|---|---|---|
属性orientation | 简介 方向 | 类型"horizontal" | "vertical" | 默认值"horizontal" | 必须false |
属性value | 简介 受控值 | 类型string | 默认值- | 必须false |
属性defaultValue | 简介 默认值 | 类型string | 默认值- | 必须true |
属性onChange | 简介 onChange 回调 | 类型(value: string) => void | 默认值- | 必须false |
TabsTab
属性 | 类型 | 默认值 | 必须 | |
---|---|---|---|---|
属性value | 简介 将内容与触发器关联起来的唯一值 | 类型string | 默认值- | 必须true |
属性disabled | 简介 是否禁用 | 类型boolean | 默认值false | 必须false |
TabsPanel
属性 | 类型 | 默认值 | 必须 | |
---|---|---|---|---|
属性value | 简介 将内容与触发器关联起来的唯一值 | 类型string | 默认值- | 必须true |