Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test has a WPT meta file that expects 18 subtest issues.
- This WPT test may be referenced by the following Test IDs:
- /html/interaction/focus/focusgroup/tentative/behavior-tokens-comprehensive.html - WPT Dashboard Interop Dashboard
<!DOCTYPE html>
<meta charset="utf-8">
<title>HTML Test: focusgroup - Default axis and wrap per behavior token</title>
<meta name="assert" content="Each behavior token provides default axis and wrap modifiers. Explicit modifiers override defaults. 'none' disables navigation.">
<link rel="author" title="Microsoft" href="http://www.microsoft.com/">
<link rel="help" href="https://open-ui.org/components/scoped-focusgroup.explainer/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/shadow-dom/focus-navigation/resources/focus-utils.js"></script>
<script src="resources/focusgroup-utils.js"></script>
<!-- toolbar: inline only, no wrap -->
<div focusgroup="toolbar">
<button id=tb1>tb1</button>
<button id=tb2>tb2</button>
<button id=tb3>tb3</button>
</div>
<!-- tablist: inline + wrap -->
<div focusgroup="tablist">
<button id=tl1>tl1</button>
<button id=tl2>tl2</button>
<button id=tl3>tl3</button>
</div>
<!-- menu: block + wrap -->
<div focusgroup="menu">
<button id=m1>m1</button>
<button id=m2>m2</button>
<button id=m3>m3</button>
</div>
<!-- menubar: inline + wrap -->
<div focusgroup="menubar">
<button id=mb1>mb1</button>
<button id=mb2>mb2</button>
<button id=mb3>mb3</button>
</div>
<!-- radiogroup: no default axis, no wrap -->
<div focusgroup="radiogroup">
<button id=rg1>rg1</button>
<button id=rg2>rg2</button>
<button id=rg3>rg3</button>
</div>
<!-- listbox: no default axis, no wrap -->
<div focusgroup="listbox">
<button id=lb1>lb1</button>
<button id=lb2>lb2</button>
<button id=lb3>lb3</button>
</div>
<!-- grid: both axes, multiple rows -->
<table focusgroup="grid">
<tr>
<td id=g1 tabindex=0>g1</td>
<td id=g2 tabindex=0>g2</td>
</tr>
<tr>
<td id=g3 tabindex=0>g3</td>
<td id=g4 tabindex=0>g4</td>
</tr>
</table>
<!-- none: opt-out -->
<div focusgroup="none">
<button id=n1>n1</button>
<button id=n2>n2</button>
</div>
<!-- tablist block: explicit block overrides default inline -->
<div focusgroup="tablist block">
<button id=tlb1>tlb1</button>
<button id=tlb2>tlb2</button>
<button id=tlb3>tlb3</button>
</div>
<!-- tablist nowrap: suppresses default wrap -->
<div focusgroup="tablist nowrap">
<button id=tlnw1>tlnw1</button>
<button id=tlnw2>tlnw2</button>
<button id=tlnw3>tlnw3</button>
</div>
<!-- menu inline: explicit inline overrides default block -->
<div focusgroup="menu inline">
<button id=mi1>mi1</button>
<button id=mi2>mi2</button>
<button id=mi3>mi3</button>
</div>
<script>
// --- toolbar: inline only, no wrap ---
promise_test(async t => {
await focusAndKeyPress(document.getElementById('tb1'), kArrowRight);
assert_equals(document.activeElement.id, 'tb2');
}, "toolbar: ArrowRight navigates (inline)");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('tb1'), kArrowDown);
assert_equals(document.activeElement.id, 'tb1');
}, "toolbar: ArrowDown blocked (inline-only)");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('tb3'), kArrowRight);
assert_equals(document.activeElement.id, 'tb3');
}, "toolbar: does not wrap");
// --- tablist: inline + wrap ---
promise_test(async t => {
await focusAndKeyPress(document.getElementById('tl1'), kArrowRight);
assert_equals(document.activeElement.id, 'tl2');
}, "tablist: ArrowRight navigates (inline)");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('tl1'), kArrowDown);
assert_equals(document.activeElement.id, 'tl1');
}, "tablist: ArrowDown blocked (inline-only)");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('tl3'), kArrowRight);
assert_equals(document.activeElement.id, 'tl1');
}, "tablist: wraps");
// --- menu: block + wrap ---
promise_test(async t => {
await focusAndKeyPress(document.getElementById('m1'), kArrowDown);
assert_equals(document.activeElement.id, 'm2');
}, "menu: ArrowDown navigates (block)");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('m1'), kArrowRight);
assert_equals(document.activeElement.id, 'm1');
}, "menu: ArrowRight blocked (block-only)");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('m3'), kArrowDown);
assert_equals(document.activeElement.id, 'm1');
}, "menu: wraps");
// --- menubar: inline + wrap ---
promise_test(async t => {
await focusAndKeyPress(document.getElementById('mb1'), kArrowRight);
assert_equals(document.activeElement.id, 'mb2');
}, "menubar: ArrowRight navigates (inline)");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('mb1'), kArrowDown);
assert_equals(document.activeElement.id, 'mb1');
}, "menubar: ArrowDown blocked (inline-only)");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('mb3'), kArrowRight);
assert_equals(document.activeElement.id, 'mb1');
}, "menubar: wraps");
// --- radiogroup: both axes, no wrap ---
promise_test(async t => {
await focusAndKeyPress(document.getElementById('rg1'), kArrowRight);
assert_equals(document.activeElement.id, 'rg2');
}, "radiogroup: ArrowRight navigates");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('rg1'), kArrowDown);
assert_equals(document.activeElement.id, 'rg2');
}, "radiogroup: ArrowDown navigates");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('rg3'), kArrowRight);
assert_equals(document.activeElement.id, 'rg3');
}, "radiogroup: does not wrap");
// --- listbox: both axes, no wrap ---
promise_test(async t => {
await focusAndKeyPress(document.getElementById('lb1'), kArrowRight);
assert_equals(document.activeElement.id, 'lb2');
}, "listbox: ArrowRight navigates");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('lb1'), kArrowDown);
assert_equals(document.activeElement.id, 'lb2');
}, "listbox: ArrowDown navigates");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('lb3'), kArrowRight);
assert_equals(document.activeElement.id, 'lb3');
}, "listbox: does not wrap");
// --- grid: both axes ---
promise_test(async t => {
await focusAndKeyPress(document.getElementById('g1'), kArrowRight);
assert_equals(document.activeElement.id, 'g2');
}, "grid: ArrowRight navigates (inline)");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('g1'), kArrowDown);
assert_equals(document.activeElement.id, 'g3');
}, "grid: ArrowDown navigates (block, same column)");
// --- none: all navigation disabled ---
promise_test(async t => {
const n1 = document.getElementById('n1');
await focusAndKeyPress(n1, kArrowRight);
assert_equals(document.activeElement.id, 'n1');
await focusAndKeyPress(n1, kArrowDown);
assert_equals(document.activeElement.id, 'n1');
}, "none: no navigation");
// --- Modifier overrides ---
// tablist block: explicit block overrides default inline.
promise_test(async t => {
await focusAndKeyPress(document.getElementById('tlb1'), kArrowDown);
assert_equals(document.activeElement.id, 'tlb2');
}, "tablist block: ArrowDown navigates");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('tlb1'), kArrowRight);
assert_equals(document.activeElement.id, 'tlb1');
}, "tablist block: ArrowRight blocked");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('tlb3'), kArrowDown);
assert_equals(document.activeElement.id, 'tlb1');
}, "tablist block: wraps");
// tablist nowrap: suppresses default wrap.
promise_test(async t => {
await focusAndKeyPress(document.getElementById('tlnw1'), kArrowRight);
assert_equals(document.activeElement.id, 'tlnw2');
}, "tablist nowrap: ArrowRight navigates");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('tlnw3'), kArrowRight);
assert_equals(document.activeElement.id, 'tlnw3');
}, "tablist nowrap: does not wrap");
// menu inline: explicit inline overrides default block.
promise_test(async t => {
await focusAndKeyPress(document.getElementById('mi1'), kArrowRight);
assert_equals(document.activeElement.id, 'mi2');
}, "menu inline: ArrowRight navigates");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('mi1'), kArrowDown);
assert_equals(document.activeElement.id, 'mi1');
}, "menu inline: ArrowDown blocked");
promise_test(async t => {
await focusAndKeyPress(document.getElementById('mi3'), kArrowRight);
assert_equals(document.activeElement.id, 'mi1');
}, "menu inline: wraps");
</script>