Tabs
Switchable tabbed content panels.
Code
components/Tabs.astro
---interface Tab { label: string;} interface Props { tabs: Tab[]; activeIndex?: number; class?: string;} const { tabs, activeIndex = 0, class: className = "",} = Astro.props;--- <div class={`tabs ${className}`}> <div class="tab-list" role="tablist"> {tabs.map((tab, i) => ( <button class={`tab-btn ${i === activeIndex ? "tab-btn-active" : ""}`} role="tab" aria-selected={i === activeIndex} > {tab.label} </button> ))} </div> <div class="tab-panels"> <slot /> </div></div> <script> document.querySelectorAll(".tabs").forEach((tabs) => { const tabButtons = tabs.querySelectorAll(".tab-btn"); const panels = tabs.querySelectorAll("[data-tab-panel]"); function activateTab(index) { tabButtons.forEach((btn, i) => { btn.classList.toggle("tab-btn-active", i === index); btn.setAttribute("aria-selected", i === index); }); panels.forEach((panel, i) => { panel.classList.toggle("active", i === index); }); } const activeBtn = tabs.querySelector(".tab-btn-active"); const initialIndex = activeBtn ? Array.from(tabButtons).indexOf(activeBtn) : 0; activateTab(initialIndex); tabButtons.forEach((btn, i) => { btn.addEventListener("click", () => activateTab(i)); }); });</script>
Preview
This is the preview panel with some sample content.
Details panel — additional information goes here.
Settings panel — configure your preferences.
Usage
<Tabs tabs={[{ label: "Tab 1" }, { label: "Tab 2" }]}> <div data-tab-panel="0"> <p>Content for tab 1.</p> </div> <div data-tab-panel="1"> <p>Content for tab 2.</p> </div></Tabs>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| tabs | Tab[] | — | Array of tabs with label. |
| activeIndex | number | 0 | Initially active tab index. |
| class | string | — | Additional CSS classes. |