# Example: tabs

The next `MAX_TABS` sections become tabs, named by each section's first heading, with arrow-key
navigation. It hides Squarespace sections, so it restores them in edit mode. Copy `onEditMode`
from [Squarespace](squarespace.md#the-editor) into the same IIFE. Put the constants and `init`
in the starter in place of its `ID` line and `init`. **Reads:** no attributes.

```js
const ID = "__ID__";
const MAX_TABS = 3;

function init(el) {
  const panels = [];
  for (let s = el.closest(".page-section")?.nextElementSibling; s && panels.length < MAX_TABS; s = s.nextElementSibling)
    if (s.matches(".page-section")) panels.push(s);
  if (!panels.length) return void (el.innerHTML = `<p class="sb-empty">Add sections below this block. Each becomes a tab.</p>`);
  el.innerHTML = `<div class="sb-tabs" role="tablist"></div>`;
  const list = el.firstElementChild, added = [];
  const tabs = panels.map((p, i) => {
    if (!p.id) { p.id = `sb-${ID}-panel-${i}`; added.push(p); }
    const b = document.createElement("button");
    Object.assign(b, { type: "button", id: `sb-${ID}-tab-${i}`, className: "sb-tab" });
    b.setAttribute("role", "tab"); b.setAttribute("aria-controls", p.id);
    b.textContent = p.querySelector("h1, h2, h3, h4")?.textContent.trim().slice(0, 32) || `Tab ${i + 1}`;
    p.setAttribute("role", "tabpanel"); p.setAttribute("aria-labelledby", b.id);
    p.dataset.sbPanelOf = ID;
    return list.appendChild(b);
  });
  const show = (i) => tabs.forEach((t, j) => {
    t.setAttribute("aria-selected", String(i === j));
    t.tabIndex = i === j ? 0 : -1;
    t.classList.toggle("is-active", i === j);
    panels[j].hidden = i !== j;
  });
  list.addEventListener("click", (e) => { const i = tabs.indexOf(e.target.closest(".sb-tab")); if (i >= 0) show(i); });
  list.addEventListener("keydown", (e) => {
    const step = { ArrowRight: 1, ArrowLeft: -1 }[e.key];
    if (!step) return;
    const i = (tabs.indexOf(document.activeElement) + step + tabs.length) % tabs.length;
    show(i); tabs[i].focus();
  });
  show(0);
  onEditMode(() => {
    for (const p of panels) {
      p.hidden = false; p.removeAttribute("role"); p.removeAttribute("aria-labelledby"); delete p.dataset.sbPanelOf;
    }
    for (const p of added) p.removeAttribute("id");
    el.innerHTML = "";
  });
}
```

```css
[data-sb-panel-of="__ID__"][hidden] { display: none !important; }
[data-seamble-id="__ID__"] .sb-tabs { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; padding-bottom: 8px; border-bottom: 2px solid color-mix(in srgb, currentColor 15%, transparent); }
[data-seamble-id="__ID__"] .sb-tab { font: inherit; color: inherit; background: none; border: 0; border-radius: 5px; padding: 8px 16px; min-height: 44px; cursor: pointer; }
[data-seamble-id="__ID__"] .sb-tab:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
[data-seamble-id="__ID__"] .sb-tab.is-active { background: var(--sb-accent, var(--primaryButtonBackgroundColor, #111)); color: var(--sb-on-accent, var(--siteBackgroundColor, #fff)); }
[data-seamble-id="__ID__"] .sb-empty { opacity: 0.6; font-size: 0.9em; }
```
