v150 · html · shipped
Focusgroup
A new HTML attribute that gives any container arrow-key navigation, a single tab stop, and last-focused memory — the "roving tabindex" pattern — without any JavaScript.
at a glance
| Shipped in | Chrome 150 (desktop + Android) |
|---|---|
| Status | Enabled by default |
| Flag | None (was chrome://flags/#experimental-web-platform-features) |
| Standards position | Supported by Microsoft Edge team (co-authored spec) |
| Spec | Open UI — focusgroup explainer |
| Explainer | MicrosoftEdge / MSEdgeExplainers / Focusgroup |
| ChromeStatus | 5637601087193088 — Focusgroup |
why it exists
Accessible keyboard navigation for composite widgets — toolbars, tablists, menus, listboxes — requires implementing the "roving tabindex" pattern: one item in the group has tabindex="0" and all others have tabindex="-1"; arrow keys move focus and update which item holds the zero index. This is correct per ARIA but requires dozens of lines of JavaScript to implement reliably, handle edge cases (wrap, grid navigation, focus memory after Tab away), and stay correct across DOM mutations. The focusgroup attribute delegates all of this to the browser.
shape of the API
Add the focusgroup attribute to any container element. All sequentially focusable descendants automatically become focusgroup items. The group collapses to a single Tab stop; arrow keys move within it.
syntax
<element focusgroup="[tokens]">
The attribute value is a space-separated list of optional tokens. An empty string or focusgroup with no value uses all defaults.
tokens
| Token | Effect |
|---|---|
horizontal | Only left/right arrow keys navigate within the group. Tab still exits. Default when neither axis token is specified is both axes. |
vertical | Only up/down arrow keys navigate within the group. |
wrap | Arrow navigation wraps around: pressing right at the last item focuses the first, and vice versa. |
extend | This focusgroup joins the nearest ancestor focusgroup, merging into a single roving scope. Useful for building nested toolbars. |
grid | Enables two-dimensional navigation for tabular structures. Arrow keys move by row and column. |
row-wrap / col-wrap | Wrap-around along a specific axis in grid mode. |
row-flow / col-flow | When reaching the end of a row/column in grid mode, flow to the next row/column rather than wrapping in-place. |
examples
toolbar: horizontal-only, wrapping
<div role="toolbar" focusgroup="horizontal wrap">
<button>Bold</button>
<button>Italic</button>
<button>Underline</button>
</div>
Tab enters the toolbar and focuses the last-remembered item. Left/right arrows cycle through; right at the end wraps back to Bold.
live demo (Chrome 150+)
Tab to this toolbar, then use left/right arrow keys:
tablist: vertical focus group
<div role="tablist" focusgroup="vertical">
<button role="tab" aria-selected="true">Tab 1</button>
<button role="tab" aria-selected="false">Tab 2</button>
<button role="tab" aria-selected="false">Tab 3</button>
</div>
grid navigation
<table focusgroup="grid">
<tr><td><button>A1</button></td><td><button>A2</button></td></tr>
<tr><td><button>B1</button></td><td><button>B2</button></td></tr>
</table>
<!-- Up/down moves between rows; left/right moves between columns -->
nested groups with extend
<div focusgroup="horizontal">
<button>Cut</button>
<button>Copy</button>
<!-- This sub-toolbar joins the parent's focusgroup scope: -->
<div focusgroup="horizontal extend">
<button>Paste</button>
<button>Paste Special</button>
</div>
</div>
last-focused memory
When the user Tabs away from a focusgroup and later Tabs back in, focus restores to the last item that held focus within the group — not always the first item. This matches the ARIA authoring practices "roving tabindex" recommendation and avoids forcing keyboard users to navigate from the beginning every time.
Pass nomemory (if supported) to opt out and always restore to the first item.
browser support
| Chrome / Edge | 150 (enabled by default); experimental flag from 146 |
|---|---|
| Firefox | No signal |
| Safari | No signal |