Skip to content

Commit

Permalink
Scrollable Listbox Example: Ad default value 'None' so first item can…
Browse files Browse the repository at this point in the history
… be focusable on load (pull #3139)

Fixes issue #3138 by adding a new value of 'None' to the list of options and focusing that option by default. This makes the example consistent with the pattern guidance.
  • Loading branch information
wagnermaciel authored Nov 19, 2024
1 parent 3c8b715 commit b0c04c4
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ class ListboxButton {
case 'ArrowDown':
evt.preventDefault();
this.showListbox();
this.listbox.checkKeyPress(evt);
break;
}
}
Expand Down
2 changes: 2 additions & 0 deletions content/patterns/listbox/examples/js/listbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ aria.Listbox = class Listbox {
if (this.activeDescendant) {
const listitem = document.getElementById(this.activeDescendant);
listitem.scrollIntoView({ block: 'nearest', inline: 'nearest' });
} else {
this.focusFirstItem();
}
}

Expand Down
1 change: 1 addition & 0 deletions content/patterns/listbox/examples/listbox-collapsible.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ <h2 id="ex_label">Example</h2>
<div id="exp_wrapper">
<button type="button" aria-haspopup="listbox" aria-labelledby="exp_elem exp_button" id="exp_button">Neptunium</button>
<ul id="exp_elem_list" tabindex="-1" role="listbox" aria-labelledby="exp_elem" class="hidden">
<li id="exp_elem_None" role="option">None</li>
<li id="exp_elem_Np" role="option">Neptunium</li>
<li id="exp_elem_Pu" role="option">Plutonium</li>
<li id="exp_elem_Am" role="option">Americium</li>
Expand Down
4 changes: 4 additions & 0 deletions content/patterns/listbox/examples/listbox-scrollable.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ <h2 id="ex_label">Example</h2>
<div>
<span id="ss_elem" class="listbox-label">Transuranium elements:</span>
<ul id="ss_elem_list" tabindex="0" role="listbox" aria-labelledby="ss_elem">
<li id="ss_elem_None" role="option">
<span class="checkmark" aria-hidden="true"></span>
None
</li>
<li id="ss_elem_Np" role="option">
<span class="checkmark" aria-hidden="true"></span>
Neptunium
Expand Down
38 changes: 21 additions & 17 deletions test/tests/listbox_collapsible.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const ex = {
buttonSelector: '#ex button',
listboxSelector: '#ex [role="listbox"]',
optionSelector: '#ex [role="option"]',
numOptions: 26,
numOptions: 27,
};

const checkFocus = async function (t, selector) {
Expand Down Expand Up @@ -132,23 +132,27 @@ ariaTest(
By.css(ex.listboxSelector)
);
const options = await t.context.queryElements(t, ex.optionSelector);
const optionId = await options[0].getAttribute('id');
const optionId0 = await options[0].getAttribute('id');
const optionId1 = await options[1].getAttribute('id');

// no active descendant is expected until arrow keys are used
// The first active descendant is selected
t.is(
await listbox.getAttribute('aria-activedescendant'),
null,
'activedescendant not set on open click'
optionId0,
'aria-activedescendant should be set to ' +
optionId0 +
' for items: ' +
ex.listboxSelector
);

// active descendant set to first item on down arrow
// The active descendant moves to the second item on down arrow
await listbox.sendKeys(Key.DOWN);

t.is(
await listbox.getAttribute('aria-activedescendant'),
optionId,
optionId1,
'aria-activedescendant should be set to ' +
optionId +
optionId1 +
' for items: ' +
ex.listboxSelector
);
Expand All @@ -160,7 +164,7 @@ ariaTest(
exampleFile,
'option-role',
async (t) => {
await assertAriaRoles(t, 'ex', 'option', 26, 'li');
await assertAriaRoles(t, 'ex', 'option', 27, 'li');
}
);

Expand Down Expand Up @@ -444,7 +448,7 @@ ariaTest(
// will automatically select the first option.
await t.context.session.findElement(By.css(ex.buttonSelector)).click();

// The third item is 'Americium'
// The fourth item is 'Americium'
let listbox = await t.context.session.findElement(
By.css(ex.listboxSelector)
);
Expand All @@ -453,7 +457,7 @@ ariaTest(
t,
ex.listboxSelector,
ex.optionSelector,
2
3
);

// Reload page
Expand All @@ -464,14 +468,14 @@ ariaTest(
await t.context.session.findElement(By.css(ex.buttonSelector)).click();

// Keys in rapid session will treat characters like first few characters of item
// In this cae, 'Curium' at index 3 will be skipped for 'Californium' at index 5
// In this cae, 'Curium' at index 4 will be skipped for 'Californium' at index 6
listbox = await t.context.session.findElement(By.css(ex.listboxSelector));
await listbox.sendKeys('c', 'a');
await assertAriaSelectedAndActivedescendant(
t,
ex.listboxSelector,
ex.optionSelector,
5
6
);

// Reload page
Expand All @@ -483,25 +487,25 @@ ariaTest(

listbox = await t.context.session.findElement(By.css(ex.listboxSelector));

// With a break, sending on 'b' will land us on 'Berkelium' at index 4
// With a break, sending on 'b' will land us on 'Berkelium' at index 5
await listbox.sendKeys('b');
await assertAriaSelectedAndActivedescendant(
t,
ex.listboxSelector,
ex.optionSelector,
4
5
);

// Wait for half a second before sending second 'b'
await new Promise((resolve) => setTimeout(resolve, 500));

// A second 'b' should land us on 'Bohrium' at index 14
// A second 'b' should land us on 'Bohrium' at index 15
await listbox.sendKeys('b');
await assertAriaSelectedAndActivedescendant(
t,
ex.listboxSelector,
ex.optionSelector,
14
15
);
}
);
6 changes: 3 additions & 3 deletions test/tests/listbox_grouped.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,11 @@ ariaTest(
);

ariaTest(
'DOWN ARROW sends initial focus to the first option',
'DOWN ARROW moves focus to the second option',
exampleFile,
'key-down-arrow',
async (t) => {
// Sending the key down arrow will put focus on the first option if no options are focused
// Sending the key down arrow will move focus to the second option.
const listbox = await t.context.session.findElement(
By.css(ex.listboxSelector)
);
Expand All @@ -190,7 +190,7 @@ ariaTest(
t,
ex.listboxSelector,
ex.optionSelector,
0
1
);
}
);
Expand Down
6 changes: 3 additions & 3 deletions test/tests/listbox_scrollable.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ const ex = {
listboxSelector: '#ex [role="listbox"]',
optionSelector: '#ex [role="option"]',
spanSelector: '#ex [role="option"] span.checkmark',
numOptions: 26,
firstOptionSelector: '#ex #ss_elem_Np',
numOptions: 27,
firstOptionSelector: '#ex #ss_elem_None',
};

// Attributes
Expand Down Expand Up @@ -75,7 +75,7 @@ ariaTest(
exampleFile,
'option-role',
async (t) => {
await assertAriaRoles(t, 'ex', 'option', 26, 'li');
await assertAriaRoles(t, 'ex', 'option', 27, 'li');
}
);

Expand Down

0 comments on commit b0c04c4

Please sign in to comment.