src/tabs-widget.tsTypeScript
@@ -0,0 +1,51 @@
1+
export interface TabDefinition {2+
id: string;3+
label: string;4+
content: string;5+
disabled?: boolean;6+
}7+
8+
export function mountTabs(root: HTMLElement, definitions: TabDefinition[]): void {9+
const tabList = document.createElement("div");10+
tabList.setAttribute("role", "tablist");11+
12+
const buttons: HTMLButtonElement[] = [];13+
const panels: HTMLElement[] = [];14+
15+
function select(selectedIndex: number): void {16+
buttons.forEach((button, index) => {17+
button.setAttribute("aria-selected", String(index === selectedIndex));18+
});19+
panels.forEach((panel, index) => {20+
panel.hidden = index !== selectedIndex;21+
});22+
}23+
24+
definitions.forEach((definition, index) => {25+
const button = document.createElement("button");26+
button.type = "button";27+
button.id = `tab-${definition.id}`;28+
button.textContent = definition.label;29+
button.setAttribute("role", "tab");30+
button.setAttribute("aria-controls", "tab-panel");31+
button.tabIndex = 0;32+
button.addEventListener("click", () => select(index));33+
button.addEventListener("keydown", (event) => {34+
if (event.key === "ArrowRight") {35+
buttons[index + 1]?.focus();36+
}37+
});38+
39+
const panel = document.createElement("section");40+
panel.id = "tab-panel";41+
panel.textContent = definition.content;42+
43+
buttons.push(button);44+
panels.push(panel);45+
tabList.append(button);46+
root.append(panel);47+
});48+
49+
root.prepend(tabList);50+
select(0);51+
}