Skip to content

Commit 8124fee

Browse files
committed
fix(a11y): remove aria-describedby attribute when no descriptions are left
Currently the `AriaDescriber` will leave an empty `aria-describedby` attribute once all of the descriptions have been removed. These changes remove the attribute completely in order to avoid potential a11y issues. Fixes #17070.
1 parent 31d8819 commit 8124fee

File tree

3 files changed

+18
-2
lines changed

3 files changed

+18
-2
lines changed

src/cdk/a11y/aria-describer/aria-describer.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,18 @@ describe('AriaDescriber', () => {
226226
'Expected description node to still be in the DOM after it is no longer being used.');
227227
});
228228

229+
it('should remove the aria-describedby attribute if there are no more messages', () => {
230+
const element = component.element1;
231+
232+
expect(element.hasAttribute('aria-describedby')).toBe(false);
233+
234+
ariaDescriber.describe(component.element1, 'Message');
235+
expect(element.hasAttribute('aria-describedby')).toBe(true);
236+
237+
ariaDescriber.removeDescription(component.element1, 'Message');
238+
expect(element.hasAttribute('aria-describedby')).toBe(false);
239+
});
240+
229241
});
230242

231243
function getMessagesContainer() {

src/cdk/a11y/aria-describer/aria-reference.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,6 @@ describe('AriaReference', () => {
6363
*/
6464
function expectIds(attr: string, ids: string[]) {
6565
expect(getAriaReferenceIds(testElement!, attr)).toEqual(ids);
66-
expect(testElement!.getAttribute(attr)).toBe(ids.length ? ids.join(' ') : '');
66+
expect(testElement!.getAttribute(attr)).toBe(ids.length ? ids.join(' ') : null);
6767
}
6868
});

src/cdk/a11y/aria-describer/aria-reference.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ export function removeAriaReferencedId(el: Element, attr: string, id: string) {
2929
const ids = getAriaReferenceIds(el, attr);
3030
const filteredIds = ids.filter(val => val != id.trim());
3131

32-
el.setAttribute(attr, filteredIds.join(ID_DELIMINATOR));
32+
if (filteredIds.length) {
33+
el.setAttribute(attr, filteredIds.join(ID_DELIMINATOR));
34+
} else {
35+
el.removeAttribute(attr);
36+
}
3337
}
3438

3539
/**

0 commit comments

Comments
 (0)