Tabs
Tabs turn headings into tab labels. Every direct child heading at the first heading's level starts a tab; deeper headings are content. This is the cleanest degradation in the vocabulary, which is why tabs use headings rather than a separator: a stock renderer shows the headings and their content, in order.
Tab state uses radio inputs, so no JavaScript is involved. active=<n> picks the initially open tab.
Attributes
| Attribute | Values | Default |
|---|---|---|
active |
A positive integer within the tab count | 1 |
Content must be headings and their blocks. The first heading found sets the tab level; every heading at that level starts a new tab and anything deeper is content inside it. Content before the first heading is an error, as is a heading shallower than the first.
Downgrade: the headings and their content, unchanged. This is the cleanest fallback in the vocabulary, and it is the reason tabs use headings rather than a separator.
Watch for: tab groups do not synchronize. Radio inputs cannot do it without a script, and scripts are out of scope.
Examples
Headings become the tab labels. A renderer with no tab support shows the sections one after another, which is the downgrade.
canonical
Source
:::tabs
### macOS
`brew install markset`
### Windows
`winget install markset`
:::
Rendered
brew install markset
winget install markset
Downgrade
### macOS
`brew install markset`
### Windows
`winget install markset`
active picks which tab opens. Panels switch with radio inputs, so there is no script.
active tab override
Source
:::tabs{active=2}
## A
a
## B
b
:::
Rendered
a
b
Downgrade
## A
a
## B
b
The first heading level found sets the tab level. Anything deeper is content inside that tab.
deeper headings are tab content
Source
:::tabs
## A
### Sub
text
## B
:::
Rendered
Sub
text
Downgrade
## A
### Sub
text
## B
Tab content is ordinary blocks, so constructs nest inside it with the usual fence rule.
nested: a card inside a tab
Source
::::tabs
### A
:::card
x
:::
### B
y
::::
Rendered
x
y
Downgrade
### A
x
### B
y
What the validator catches
Every error below is specified; nothing degrades silently.
empty content
invalid
Source
:::tabs
:::
Rendered
Diagnostics: TABS_NO_HEADINGS
wrong content type: no headings
invalid
Source
:::tabs
just text
:::
Rendered
just text
Diagnostics: TABS_NO_HEADINGS
content before the first heading
invalid
Source
:::tabs
intro
### A
x
:::
Rendered
intro
A
x
Diagnostics: TABS_CONTENT_BEFORE_HEADING
All 15 cases for tabs are in the conformance browser. The normative text is spec §4.