Skip to content

Instantly share code, notes, and snippets.

@mg901
Last active June 9, 2026 13:02
Show Gist options
  • Select an option

  • Save mg901/adcd38ad59871f70215fa43536a7ab2d to your computer and use it in GitHub Desktop.

Select an option

Save mg901/adcd38ad59871f70215fa43536a7ab2d to your computer and use it in GitHub Desktop.
Tabs III
import { useId, useRef, useState } from "react";
export default function Tabs({ defaultValue, items = [] }) {
const id = useId();
const tabsRef = useRef([]);
const [activeValue, setActiveValue] = useState(
defaultValue ?? items[0]?.value,
);
const activate = (index) => {
setActiveValue(items[index].value);
tabsRef.current[index].focus();
};
const handleKeyDown = (e, index) => {
const n = items.length;
const { key } = e;
if (key === "ArrowLeft") {
const prevIndex = (index - 1 + n) % n;
activate(prevIndex);
e.preventDefault();
} else if (key === "ArrowRight") {
const nextIndex = (index + 1) % n;
activate(nextIndex);
e.preventDefault();
} else if (key === "Home") {
activate(0);
e.preventDefault();
} else if (key === "End") {
activate(n - 1);
e.preventDefault();
}
};
return (
<div className="tabs">
<div className="tabs-list" role="tablist">
{items.map(({ value, label }, index) => {
const selected = activeValue === value;
return (
<button
key={value}
tabIndex={selected ? 0 : -1}
type="button"
id={`${id}-tab-${index}`}
role="tab"
aria-controls={`${id}-panel-${index}`}
aria-selected={selected}
data-active={selected}
className="tabs-list-item"
onKeyDown={(e) => handleKeyDown(e, index)}
onClick={() => activate(index)}
ref={(node) => {
tabsRef.current[index] = node;
}}
>
{label}
</button>
);
})}
</div>
<div>
{items.map(({ value, panel }, index) => {
const selected = activeValue === value;
return (
<div
key={value}
tabIndex={0}
id={`${id}-panel-${index}`}
role="tabpanel"
aria-labelledby={`${id}-tab-${index}`}
className="tab-panel"
data-active={selected}
hidden={!selected}
>
{panel}
</div>
);
})}
</div>
</div>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment