← CSS scroll-marker-group modes
v154 · css · value reference
tabs mode
The generated ::scroll-marker-group “operates in ‘tabs’ mode, functioning like a tablist” — a native, declarative implementation of the WAI-ARIA Tabs Pattern: tablist/tab/tabpanel roles, a roving tab stop with arrow-key navigation, focus that moves from the active tab straight into its panel, and automatic accessibility-tree pruning of inactive panels.
Syntax
/* mode keyword combined with a position keyword (either order) */
scroll-marker-group: after tabs;
scroll-marker-group: tabs before;
tabs is one of the two mode keywords in the grammar none | [ [ before | after ] || [ links | tabs ] ] (quoted verbatim from the propdef). The spec’s value definition, in full: “The generated ::scroll-marker-group operates in ‘tabs’ mode, functioning like a tablist.” Unlike links, tabs semantics are never applied implicitly — the keyword must be present.
tabs; propdef (fetched 2026-10-04)
Inputs
tabs is a bare keyword and takes no arguments. It combines with at most one position keyword (before | after) via the || combinator, in either order, and cannot be combined with none or with links. The grammar permits scroll-marker-group: tabs with no position keyword, but the spec prose read on 2026-10-04 defines the group box’s placement only for before and after — include a position keyword in practice.
Outputs: roles and focus behavior
Per CSS Overflow 5 §3.1.6, when the mode is tabs:
- “The roles of ::scroll-marker-group and ::scroll-marker are
tablistandtabrespectively.” - The group “implicitly behaves as a single focusable component, establishing a focusgroup”.
- “Only the active ::scroll-marker is a tab stop; arrow keys are used to switch between markers.” Markers behave as if they had
tabindex="-1", with a guaranteed tab stop when the group would otherwise have none (the first marker). - “Originating elements of ::scroll-marker are given an implicit role of
tabpanel.” If the originating element is a::columnpseudo-element, thetabpanelrole goes to the column’s originating element. - “The ::scroll-marker pseudo-element is a focus navigation scope owner for its associated originating element” — pressing Tab from the active marker moves focus into the active panel’s content, and inactive panels’ contents are unreachable until their tab is activated.
- “Content from inactive tabs is also hidden from the accessibility tree”, so authors “do not need to carefully apply
interactivity: inertto hide the inactive tabpanels”.
This is the roving-tabindex tablist of the WAI-ARIA Tabs Pattern, produced declaratively: a 20-dot carousel is one tab stop, not twenty.
Source: CSS Overflow 5 §3.1.6 (quoted verbatim); explainer (Tabs Pattern mapping, a11y tree)Errors
A CSS keyword value has no exception surface. A declaration that does not match the grammar (for example scroll-marker-group: tabs links, which repeats the mode slot) is syntactically invalid and the declaration is ignored, per standard CSS error handling; in browsers without mode support (Chrome ≤ 153, and the links/tabs keywords entirely in Firefox/Safari) the declaration likewise fails to parse and falls back to any earlier valid declaration. Feature-detect with CSS.supports("scroll-marker-group", "after tabs") and keep an earlier scroll-marker-group: after declaration as the fallback.
Context and prerequisites
scroll-marker-group applies to scroll containers (propdef “Applies to” line). Markers appear only when descendants also generate ::scroll-marker pseudo-elements with a non-none computed content value; those markers are collected into the ::scroll-marker-group of the nearest scroll container ancestor. The mode is read from the scroll-marker-group value of the group’s originating element. Works with fragmentation: markers originating from ::column pseudo-elements (column-based carousels) assign the tabpanel role to the column’s originating element. Available without flags from Chrome 154 (runtime flag CSSScrollMarkerGroupModes, status stable).
Lifecycle: activation
Activating a tabs-mode marker (by explicit invocation or by arrow-key focus — note that in tabs mode, focusing a marker with the arrow keys activates it) scrolls its scroll target into view (block/inline alignment “start”) and, on invocation, follows the hyperlink, updating the URL. Then, specific to tabs mode: the browser will “Retain focus on the scroll marker element” — exactly how standard tabs operate. The spec adds: “In tabs mode, if the user tabs away, the focus behavior will ensure they tab into the relevant content.” The active marker tracks scrolling (:target-current), and switching tabs swaps which panel’s content is exposed to focus and the accessibility tree.
Examples
A tabbed carousel, adapted from the explainer’s tabs-mode example (live upstream demo: CodePen):
<style>
.slides {
/* Core tabs mode property */
scroll-marker-group: after tabs;
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
&::scroll-marker-group {
text-align: center;
padding: 0.5rem;
}
& > div {
min-width: 100%;
scroll-snap-align: center;
/* Individual tab markers */
&::scroll-marker {
content: "";
display: inline-block;
width: 1rem; height: 1rem;
border-radius: 50%;
border: 1px solid #444;
margin: 0 0.2rem;
}
/* Active tab marker */
&::scroll-marker:target-current {
background: SelectedItem;
}
}
}
</style>
<div class="slides">
<div title="Introduction"><h3>Introduction</h3><p>Tab 1 content...</p></div>
<div title="Focus"><h3>Focus Behaviors</h3><p>Tab 2 content...</p></div>
<div title="Roles"><h3>Accessibility Roles</h3><p>Tab 3 content...</p></div>
</div>
The resulting accessibility tree (per the explainer) is a tabList of three tab elements with posInSet/setSize, one selected; only the active slide’s content appears as a tabPanel — inactive slides are pruned. A live interactive comparison of both modes is embedded on the feature overview.
Compatibility
| Browser | tabs value | Evidence |
|---|---|---|
| Chrome | 154 (desktop, Android, WebView) — interim: no BCD entry yet | ChromeStatus; runtime flag stable |
| Edge | Unknown — no BCD record for the mode values as of 2026-10-04 | BCD (base property only) |
| Firefox | Not shipped (base property also unshipped) | BCD version_added: false; no position |
| Safari | Not shipped (base property also unshipped) | BCD version_added: false; no position |
In Chrome 135–153 a two-keyword declaration such as scroll-marker-group: after tabs fails to parse entirely — so on its own it would remove the marker group there. Declare the plain positional value first and layer the mode on top (see Errors).
Security and privacy
CSS Overflow 5 declares that it “introduces no new privacy considerations” and “no new security considerations” (Appendices C and D). The accessibility consequence specific to tabs mode is deliberate and documented: content of inactive panels is hidden from the accessibility tree and unreachable by sequential focus until its tab is activated. Do not place content that must always be reachable (status messages, consent controls, live regions) only inside an inactive panel of a tabs-mode scroll container — this placement guidance is gendn commentary derived from the spec’s tree-pruning behavior, not a normative warning.