选项卡
查看源代码同一页面上相关面板之间切换的组件。
演示
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={"w-auto rounded-md border border-bd-normal"}>
<TabsList className={"gap-1 border-b border-bd-normal p-1"}>
<TabsIndicator className={"-bottom-px h-0.5 w-(--wv) bg-bg-primary-emphasis"} />
<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={"flex items-center justify-center p-16 text-bg-muted"}>
<SpriteIcon name={"auto"} size={"3rem"} />
</TabsPanel>
<TabsPanel value={"light"} className={"flex items-center justify-center p-16 text-bg-muted"}>
<SpriteIcon name={"sun"} size={"3rem"} />
</TabsPanel>
<TabsPanel value={"dark"} className={"flex items-center justify-center p-16 text-bg-muted"}>
<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={"w-auto rounded-md border border-bd-normal"}
orientation={"vertical"}
defaultValue={"light"}
>
<TabsList className={"border-e border-bd-normal p-1"}>
<TabsIndicator className={"-z-1 h-(--hv) w-(--wv) rounded-md bg-bg-subtle"} />
<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={"flex items-center justify-center p-16 text-bg-muted"}>
<SpriteIcon name={"auto"} size={"3rem"} />
</TabsPanel>
<TabsPanel value={"light"} className={"flex items-center justify-center p-16 text-bg-muted"}>
<SpriteIcon name={"sun"} size={"3rem"} />
</TabsPanel>
<TabsPanel value={"dark"} className={"flex items-center justify-center p-16 text-bg-muted"}>
<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={"w-auto rounded-md border border-bd-normal"} defaultValue={"auto"}>
<TabsList className={"border-b border-bd-normal p-1"}>
<TabsIndicator className={"-bottom-px h-0.5 w-(--wv) bg-bg-primary-emphasis"} />
<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={"flex items-center justify-center p-16 text-bg-muted"}>
<SpriteIcon name={"auto"} size={"3rem"} />
</TabsPanel>
<TabsPanel value={"light"} className={"flex items-center justify-center p-16 text-bg-muted"}>
<SpriteIcon name={"sun"} size={"3rem"} />
</TabsPanel>
<TabsPanel value={"dark"} className={"flex items-center justify-center p-16 text-bg-muted"}>
<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={"w-auto min-w-90 rounded-md border border-bd-normal"}
>
<TabsList className={"border-b border-bd-normal p-1"}>
<TabsIndicator className={"-bottom-px h-0.5 w-(--wv) bg-bg-primary-emphasis"} />
{tabs.map((tab) => {
return (
<TabsTab
render={(props) => <div {...props} />}
key={tab.id}
value={tab.id}
className={"inline-flex items-center rounded-md ps-3 pe-1 select-none"}
>
{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 |