Skip to content

Commit

Permalink
Update tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
mj12albert committed Nov 28, 2024
1 parent 2cba716 commit 77e2a04
Show file tree
Hide file tree
Showing 15 changed files with 156 additions and 210 deletions.
4 changes: 0 additions & 4 deletions docs/data/api/tabs-root.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@
"props": {
"className": { "type": { "name": "union", "description": "func<br>&#124;&nbsp;string" } },
"defaultValue": { "type": { "name": "any" }, "default": "0" },
"direction": {
"type": { "name": "enum", "description": "'ltr'<br>&#124;&nbsp;'rtl'" },
"default": "'ltr'"
},
"onValueChange": { "type": { "name": "func" } },
"orientation": {
"type": { "name": "enum", "description": "'horizontal'<br>&#124;&nbsp;'vertical'" },
Expand Down
12 changes: 12 additions & 0 deletions docs/data/components/tabs/tabs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,18 @@ Base UI Tabs follow the [Tabs WAI-ARIA design pattern](https://www.w3.org/WAI/A
| <kbd>Down Arrow</kbd> | Moves focus to the next tab (when `orientation="vertical"`) and activates it if `activateOnFocus` is set. |
| <kbd>Space</kbd>, <kbd>Enter</kbd> | Activates the focused tab. |

## RTL

Place horizontal tabs inside an HTML element or component with the HTML `dir="rtl"` attribute to reverse arrow key navigation for right-to-left languages:

```jsx
<html dir="rtl">
<body>
<Tabs.Root orientation="horizontal" /> {/* RTL keyboard behavior*/}
</body>
</html>
```

### Labeling

To make the Tabs component suite accessible to assistive technology, label the `<Tabs.List />` element with `aria-label`.
Expand Down
1 change: 0 additions & 1 deletion docs/data/translations/api-docs/tabs-root/tabs-root.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
"defaultValue": {
"description": "The default value. Use when the component is not controlled. When the value is <code>null</code>, no Tab will be selected."
},
"direction": { "description": "The direction of the text." },
"onValueChange": { "description": "Callback invoked when new value is being set." },
"orientation": { "description": "The component orientation (layout flow direction)." },
"render": { "description": "A function to customize rendering of the component." },
Expand Down
5 changes: 0 additions & 5 deletions docs/reference/generated/tabs-root.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@
"default": "0",
"description": "The default value. Use when the component is not controlled.\nWhen the value is `null`, no Tab will be selected."
},
"direction": {
"type": "'ltr' | 'rtl'",
"default": "'ltr'",
"description": "The direction of the text."
},
"onValueChange": {
"type": "(value, event) => void",
"description": "Callback invoked when new value is being set."
Expand Down
266 changes: 138 additions & 128 deletions packages/react/src/tabs/root/TabsRoot.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -286,19 +286,20 @@ describe('<Tabs.Root />', () => {
const handleChange = spy();
const handleKeyDown = spy();
const { getAllByRole } = await render(
<Tabs.Root
direction={direction as Tabs.Root.Props['direction']}
onValueChange={handleChange}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={0}
>
<Tabs.List activateOnFocus={false}>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>,
<div dir={direction}>
<Tabs.Root
onValueChange={handleChange}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={0}
>
<Tabs.List activateOnFocus={false}>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>
</div>,
);
const [firstTab, , lastTab] = getAllByRole('tab');
await act(async () => {
Expand All @@ -318,19 +319,20 @@ describe('<Tabs.Root />', () => {
const handleChange = spy();
const handleKeyDown = spy();
const { getAllByRole } = await render(
<Tabs.Root
direction={direction as Tabs.Root.Props['direction']}
onValueChange={handleChange}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={1}
>
<Tabs.List activateOnFocus={false}>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>,
<div dir={direction}>
<Tabs.Root
onValueChange={handleChange}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={1}
>
<Tabs.List activateOnFocus={false}>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>
</div>,
);
const [firstTab, secondTab] = getAllByRole('tab');
await act(async () => {
Expand All @@ -352,19 +354,20 @@ describe('<Tabs.Root />', () => {
const handleChange = spy();
const handleKeyDown = spy();
const { getAllByRole } = await render(
<Tabs.Root
direction={direction as Tabs.Root.Props['direction']}
onValueChange={handleChange}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={0}
>
<Tabs.List>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>,
<div dir={direction}>
<Tabs.Root
onValueChange={handleChange}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={0}
>
<Tabs.List>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>
</div>,
);
const [firstTab, , lastTab] = getAllByRole('tab');
await act(async () => {
Expand All @@ -385,19 +388,20 @@ describe('<Tabs.Root />', () => {
const handleChange = spy();
const handleKeyDown = spy();
const { getAllByRole } = await render(
<Tabs.Root
direction={direction as Tabs.Root.Props['direction']}
onValueChange={handleChange}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={1}
>
<Tabs.List>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>,
<div dir={direction}>
<Tabs.Root
onValueChange={handleChange}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={1}
>
<Tabs.List>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>
</div>,
);
const [firstTab, secondTab] = getAllByRole('tab');
await act(async () => {
Expand All @@ -418,18 +422,19 @@ describe('<Tabs.Root />', () => {
it('skips over disabled tabs', async () => {
const handleKeyDown = spy();
const { getAllByRole } = await render(
<Tabs.Root
direction={direction as Tabs.Root.Props['direction']}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={2}
>
<Tabs.List>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} disabled />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>,
<div dir={direction}>
<Tabs.Root
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={2}
>
<Tabs.List>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} disabled />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>
</div>,
);
const [firstTab, , lastTab] = getAllByRole('tab');
await act(async () => {
Expand All @@ -451,19 +456,20 @@ describe('<Tabs.Root />', () => {
const handleChange = spy();
const handleKeyDown = spy();
const { getAllByRole } = await render(
<Tabs.Root
direction={direction as Tabs.Root.Props['direction']}
onValueChange={handleChange}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={2}
>
<Tabs.List activateOnFocus={false}>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>,
<div dir={direction}>
<Tabs.Root
onValueChange={handleChange}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={2}
>
<Tabs.List activateOnFocus={false}>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>
</div>,
);
const [firstTab, , lastTab] = getAllByRole('tab');
await act(async () => {
Expand All @@ -483,19 +489,20 @@ describe('<Tabs.Root />', () => {
const handleChange = spy();
const handleKeyDown = spy();
const { getAllByRole } = await render(
<Tabs.Root
direction={direction as Tabs.Root.Props['direction']}
onValueChange={handleChange}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={1}
>
<Tabs.List activateOnFocus={false}>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>,
<div dir={direction}>
<Tabs.Root
onValueChange={handleChange}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={1}
>
<Tabs.List activateOnFocus={false}>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>
</div>,
);
const [, secondTab, lastTab] = getAllByRole('tab');
await act(async () => {
Expand All @@ -517,19 +524,20 @@ describe('<Tabs.Root />', () => {
const handleChange = spy();
const handleKeyDown = spy();
const { getAllByRole } = await render(
<Tabs.Root
direction={direction as Tabs.Root.Props['direction']}
onValueChange={handleChange}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={2}
>
<Tabs.List>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>,
<div dir={direction}>
<Tabs.Root
onValueChange={handleChange}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={2}
>
<Tabs.List>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>
</div>,
);
const [firstTab, , lastTab] = getAllByRole('tab');
await act(async () => {
Expand All @@ -550,19 +558,20 @@ describe('<Tabs.Root />', () => {
const handleChange = spy();
const handleKeyDown = spy();
const { getAllByRole } = await render(
<Tabs.Root
direction={direction as Tabs.Root.Props['direction']}
onValueChange={handleChange}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={1}
>
<Tabs.List>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>,
<div dir={direction}>
<Tabs.Root
onValueChange={handleChange}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={1}
>
<Tabs.List>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>
</div>,
);
const [, secondTab, lastTab] = getAllByRole('tab');
await act(async () => {
Expand All @@ -583,18 +592,19 @@ describe('<Tabs.Root />', () => {
it('skips over disabled tabs', async () => {
const handleKeyDown = spy();
const { getAllByRole } = await render(
<Tabs.Root
direction={direction as Tabs.Root.Props['direction']}
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={0}
>
<Tabs.List>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} disabled />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>,
<div dir={direction}>
<Tabs.Root
onKeyDown={handleKeyDown}
orientation={orientation as Tabs.Root.Props['orientation']}
value={0}
>
<Tabs.List>
<Tabs.Tab value={0} />
<Tabs.Tab value={1} disabled />
<Tabs.Tab value={2} />
</Tabs.List>
</Tabs.Root>
</div>,
);
const [firstTab, , lastTab] = getAllByRole('tab');
await act(async () => {
Expand Down
Loading

0 comments on commit 77e2a04

Please sign in to comment.