Nested Focusgroups
A nested focusgroup creates an independent navigation scope within an outer focusgroup. Each group has its own axis, wrapping, memory, and entry point. Tab moves between groups; arrows navigate within.
- The nested toolbar is an independent scope inside the outer toolbar
- Tab moves between the outer and inner focusgroups
- Arrow keys navigate within whichever group currently has focus
- Each group can have its own wrapping/memory/axis settings
View source
<div focusgroup="toolbar inline" aria-label="Main
toolbar">
<button type="button">Save</button>
<button type="button" focusgroupstart>Print</button>
<div focusgroup="toolbar inline wrap" aria-label="Text formatting">
<button type="button">Bold</button>
<button type="button">Italic</button>
<button type="button">Underline</button>
</div>
<button type="button">Close</button>
<button type="button">Exit</button>
</div>
Opt-Out Segments with focusgroup="none"
Use focusgroup="none" to exclude specific elements
from arrow navigation
while keeping them tabbable. Arrow keys skip right over them.
- Arrow keys navigate: New → Open → Save → Close → Exit (skipping Help & Shortcuts)
- Tab still reaches Help and Shortcuts
- The dimmed buttons visually indicate they're in a
focusgroup="none"zone
View source
<div focusgroup="toolbar inline"
aria-label="Segmented toolbar">
<button type="button">New</button>
<button type="button">Open</button>
<button type="button">Save</button>
<span focusgroup="none">
<button type="button">Help</button>
<button type="button">Shortcuts</button>
</span>
<button type="button">Close</button>
<button type="button">Exit</button>
</div>
Deep Descendant Discovery
Focusgroup items don't need to be direct children. The browser
discovers focusable
descendants at any depth (unless they are inside a nested
focusgroup or focusgroup="none").
<div> and
<span> wrappers.
- Buttons are nested inside
<div><span>wrappers - Focusgroup discovers them at any depth in the DOM tree
- No flat list requirement — wrapper elements for styling are fine
View source
<div focusgroup="toolbar inline"
aria-label="Nested wrappers">
<div>
<span><button
type="button">Alpha</button></span>
<span><button type="button">Beta</button></span>
<span><button
type="button">Gamma</button></span>
</div>
</div>
CSS reading-flow Integration
When CSS changes the visual order (e.g., flex-direction:
row-reverse),
reading-flow: flex-visual tells the focusgroup to
follow the visual
order rather than the DOM source order.
reading-flow: flex-visual, arrow navigation
follows the visual left-to-right order (C → B → A), not the
DOM order (A → B → C).
- DOM order: A, B, C — but
flex-direction: row-reversevisually renders C, B, A reading-flow: flex-visualtells focusgroup to follow visual order- Right arrow from C goes to B, then A (visual left-to-right)
- Without
reading-flow, arrow keys would follow DOM order (A → B → C), which is visually backwards
View source
<div focusgroup="toolbar" aria-label="Visual
order"
style="display: flex; flex-direction: row-reverse;
reading-flow: flex-visual;">
<button type="button">A (DOM first)</button>
<button type="button">B (DOM second)</button>
<button type="button">C (DOM third)</button>
</div>
Feature Detection
Check whether the browser supports focusgroup
before relying on it.
If unsupported, you can fall back to a JavaScript-based roving
tabindex or show a notice.
View source
<script>
if ('focusgroup' in HTMLElement.prototype) {
// focusgroup is supported — use it!
console.log('focusgroup is supported');
} else {
// Not supported — fall back to JS roving tabindex
console.log('focusgroup is NOT supported');
}
</script>