
Tabs show one section at a time and let the reader pick another. They are for any content, not only code: install steps per platform, one topic per audience, or a short and a long explanation. A choice made by hand is remembered and applied to every tab group on the page that offers the same label.

## Syntax

A container directive whose body holds one `##` or `###` heading per section. The heading's text is the tab label and starts that section:

````markdown
:::tabs{group="install-beacon"}
### macOS

```bash
brew install beacon
```

### Linux

```bash
curl -fsSL https://get.example.com | sh
```

### Windows

```powershell
winget install beacon
```
:::
````

`group` is the group's key. Give each group on a page its own key; when two groups share one — the same key twice, two names that sanitize alike, or no key at all — the first keeps the ids it published and each later group's ids gain a `-2`, `-3`, … suffix, so links never land on the wrong group. The heading text is also the label the island syncs on, so two groups that both offer `Linux` switch together.

A heading may author its own link target: `### Install notes {#notes}` labels the tab `Install notes` and keeps `#notes` pointing at the section; a heading written with an `id` attribute is honored the same way. The fragment is carried onto the generated panel title, so it resolves with and without JavaScript. A malformed marker (`{#with space}`) stays as literal label text.

## Options

| Option | Type | Default | What it does |
| --- | --- | --- | --- |
| `group` | string | generated | The group's key and the prefix for its element ids. Repeats on a page gain a suffix past the first group. |
| `id` | string | — | Fallback id prefix when `group` is absent. |

## Example

:::tabs{group="tabs-example"}
### macOS

Use Homebrew, or download the `darwin` archive.

### Linux

Use the `linux` archive and put `beacon` on your `PATH`.

### Windows

Use the `windows` archive and add its folder to `Path`.
:::

## Notes

- Without JavaScript the tab list stays hidden and every section shows stacked under its title, so nothing is locked behind a control that does not run.
- Every tab, panel, and title id is unique on the page: a group that repeats another's key renders under a suffixed key, and one group's ids can never move another group's selection.
- Choosing a tab by hand is remembered in `localStorage["lateen-tabs"]` and switches every group on the page and on later pages that offers the same label.
- `?tab=` in the URL chooses a label and beats what is remembered; `?lang=` works too, because the sync module is shared with code tabs.
- Choosing a tab by hand also writes `?tab=<label>` into the address bar, keeping every other query parameter, and does not reload or move the page, so the address can be shared. A link that opens the page with that parameter starts on the same tab.
- A fragment that points at a panel, or at a heading inside one, opens that panel on load even when a shared `?tab=` would leave it closed. Following a fragment after load — an in-page link, or Back and Forward — opens the owning panel as well. Fragments and `?tab=` labels that no longer match anything are ignored, and a group that stays stacked is never touched.
- Arrow keys move between tabs, `Home` and `End` go to the ends, and the arrows follow the reading direction in right-to-left pages.
- Use [OS tabs](../os-tabs/) when the sections are operating systems and the reader's system should win, or [code tabs](../code-tabs/) when the choice is a language or package manager.
- Component islands are not wired into built pages yet, so a built site shows the no-JavaScript state — every section stacked — until island wiring lands.
