Announce the suggestion list to screen readers
The invitee input had no combobox semantics: assistive technology could not tell that the widget owns a listbox with suggestions. Mark the input as role="combobox" with aria-autocomplete="list" and an initial aria-expanded="false", point aria-controls at the list and give the JS-built list a matching id so the reference resolves.
This commit is contained in:
1 parent
5bba3a93cd
commit
a9b7fd11af
3 files changed
+20
-1
No files matched your search
@@ -30,6 +30,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
var list = document.createElement('ul');
|
var list = document.createElement('ul');
|
||||||
|
list.id = 'atocal-suggestions';
|
||||||
list.className = 'atocal-suggestions';
|
list.className = 'atocal-suggestions';
|
||||||
list.hidden = true;
|
list.hidden = true;
|
||||||
list.setAttribute('role', 'listbox');
|
list.setAttribute('role', 'listbox');
|
||||||
|
|||||||
@@ -140,6 +140,10 @@ $l = $_['l10n'];
|
|||||||
id="atocal-attendees"
|
id="atocal-attendees"
|
||||||
name="attendees"
|
name="attendees"
|
||||||
type="text"
|
type="text"
|
||||||
|
role="combobox"
|
||||||
|
aria-autocomplete="list"
|
||||||
|
aria-controls="atocal-suggestions"
|
||||||
|
aria-expanded="false"
|
||||||
list="atocal-contact-emails"
|
list="atocal-contact-emails"
|
||||||
data-search-url="<?= $h($_['contactsSearchUrl']) ?>"
|
data-search-url="<?= $h($_['contactsSearchUrl']) ?>"
|
||||||
value="<?= $h($_['attendees']) ?>"
|
value="<?= $h($_['attendees']) ?>"
|
||||||
|
|||||||
@@ -37,7 +37,9 @@ async function settle(ms = DEBOUNCE_MS) {
|
|||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
document.body.innerHTML =
|
document.body.innerHTML =
|
||||||
'<span><input id="atocal-attendees" data-search-url="' + SEARCH_URL + '"></span>';
|
'<span><input id="atocal-attendees" data-search-url="' + SEARCH_URL + '"'
|
||||||
|
+ ' role="combobox" aria-autocomplete="list"'
|
||||||
|
+ ' aria-controls="atocal-suggestions" aria-expanded="false"></span>';
|
||||||
|
|
||||||
await import('../../js/invitees.js');
|
await import('../../js/invitees.js');
|
||||||
|
|
||||||
@@ -59,6 +61,18 @@ afterEach(async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('invitee suggestions', () => {
|
describe('invitee suggestions', () => {
|
||||||
|
it('marks the input as a combobox controlling the list', () => {
|
||||||
|
expect(input.getAttribute('role')).toBe('combobox');
|
||||||
|
expect(input.getAttribute('aria-autocomplete')).toBe('list');
|
||||||
|
|
||||||
|
/* aria-controls must resolve to the list built by the widget */
|
||||||
|
const controlled = document.getElementById(
|
||||||
|
input.getAttribute('aria-controls')
|
||||||
|
);
|
||||||
|
expect(controlled).toBe(list);
|
||||||
|
expect(input.getAttribute('aria-expanded')).toBe('false');
|
||||||
|
});
|
||||||
|
|
||||||
it('renders matching contacts', async () => {
|
it('renders matching contacts', async () => {
|
||||||
fetch.mockReturnValue(response([BOB]));
|
fetch.mockReturnValue(response([BOB]));
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user