Implements accessible Tabs with List, Tab, Panel parts. Supports controlled/uncontrolled value, keyboard navigation (ArrowRight/Left/Home/End), automatic/manual activation mode, and full WAI-ARIA compliance (role=tablist/tab/tabpanel, aria-selected strings, aria-controls/labelledby wiring).
42 lines
1.3 KiB
TypeScript
42 lines
1.3 KiB
TypeScript
import type { JSX } from "solid-js";
|
|
import { splitProps } from "solid-js";
|
|
import { useTabsContext } from "./tabs-context";
|
|
|
|
/** Props for a single Tab button. */
|
|
export interface TabsTabProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
value: string;
|
|
disabled?: boolean;
|
|
children?: JSX.Element;
|
|
}
|
|
|
|
/** A single tab button. Activates the corresponding panel when clicked. */
|
|
export function TabsTab(props: TabsTabProps): JSX.Element {
|
|
const [local, rest] = splitProps(props, ["value", "disabled", "children", "onClick"]);
|
|
const ctx = useTabsContext();
|
|
|
|
const isActive = () => ctx.activeTab() === local.value;
|
|
|
|
const handleClick: JSX.EventHandler<HTMLButtonElement, MouseEvent> = (e) => {
|
|
if (typeof local.onClick === "function") local.onClick(e);
|
|
if (!local.disabled) ctx.setActiveTab(local.value);
|
|
};
|
|
|
|
return (
|
|
<button
|
|
type="button"
|
|
role="tab"
|
|
id={`${ctx.baseId}-tab-${local.value}`}
|
|
aria-selected={isActive() ? "true" : "false"}
|
|
aria-controls={`${ctx.baseId}-panel-${local.value}`}
|
|
data-value={local.value}
|
|
data-state={isActive() ? "active" : "inactive"}
|
|
tabIndex={isActive() ? 0 : -1}
|
|
disabled={local.disabled}
|
|
onClick={handleClick}
|
|
{...rest}
|
|
>
|
|
{local.children}
|
|
</button>
|
|
);
|
|
}
|