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:
stefan.tollkuehn committed 2026-10-23 14:08:59 +02:00
1 parent 5bba3a93cd
commit a9b7fd11af
3 files changed
+20 -1

No files matched your search

+15 -1
View File
@@ -37,7 +37,9 @@ async function settle(ms = DEBOUNCE_MS) {
beforeAll(async () => {
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');
@@ -59,6 +61,18 @@ afterEach(async () => {
});
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 () => {
fetch.mockReturnValue(response([BOB]));