| 1234567891011121314151617181920212223 |
- interface TabOption<T extends string> { id: T; label: string }
- interface Props<T extends string> {
- tabs: Array<TabOption<T>>;
- active: T;
- onChange: (tab: T) => void;
- ariaLabel: string;
- className?: string;
- }
- export function TabList<T extends string>({ tabs, active, onChange, ariaLabel, className = "" }: Props<T>) {
- const move = (event: React.KeyboardEvent<HTMLDivElement>) => {
- if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
- event.preventDefault();
- const index = tabs.findIndex((entry) => entry.id === active);
- const next = (index + (event.key === "ArrowRight" ? 1 : -1) + tabs.length) % tabs.length;
- onChange(tabs[next].id);
- event.currentTarget.querySelectorAll<HTMLButtonElement>('[role="tab"]')[next]?.focus();
- };
- return <div className={className} role="tablist" aria-label={ariaLabel} onKeyDown={move}>
- {tabs.map((entry) => <button key={entry.id} type="button" role="tab" tabIndex={active === entry.id ? 0 : -1} aria-selected={active === entry.id} className={active === entry.id ? "active" : ""} onClick={() => onChange(entry.id)}>{entry.label}</button>)}
- </div>;
- }
|