The rail was a row of aria-pressed toggles: every tab a Tab stop, no arrows, nothing tying a tab to its content. tablist/tab/aria-selected, one Tab stop, arrows on either axis, Home/End, and useTabPanel for aria-controls/labelledby.
22 lines
795 B
TypeScript
22 lines
795 B
TypeScript
import { useId } from "react";
|
|
|
|
// The id half of ui/Tabs (its own file so Tabs.tsx exports only components — Fast Refresh).
|
|
|
|
export const tabId = (base: string, id: string) => `${base}tab-${id}`;
|
|
export const panelId = (base: string) => `${base}panel`;
|
|
|
|
/** The ids that tie a `Tabs` to the panel it switches: pass `idBase` to the `Tabs` and spread
|
|
* `panelProps(active)` on the element that shows the selected tab's content. Takes no argument, so
|
|
* it can sit above a page's loading / error returns while the active tab is only known below. */
|
|
export function useTabPanel() {
|
|
const base = useId();
|
|
return {
|
|
idBase: base,
|
|
panelProps: (active: string) => ({
|
|
id: panelId(base),
|
|
role: "tabpanel" as const,
|
|
"aria-labelledby": tabId(base, active),
|
|
}),
|
|
};
|
|
}
|