Last month, I was asked to make an existing project more accessible. We were looking into small changes to impact the accessibility significantly, as there was not a lot of time or budget available… But when is there, really? 😉
One of the first things that I wanted to fix was making the applications more keyboard-accessible. There were two main goals in this accessibility sprint:
This blog will focus on the second goal: ensuring you can navigate through your page to all clickable items with only a keyboard.
Correct! Items like anchors and buttons have predefined roles that would allow you to navigate to them with only your keyboard. But that only applies when you correctly use HTML, which was not the case in this specific project.
We developed visual components in Angular, so clickable items could be everything: divs, icons, paragraphs, spans,... Everything that’s not a button or anchor. That’s a problem. How can we fix it?
You can fix the HTML. This should always be your first consideration, especially when starting a new project. However, it isn't always possible when you have a lot of existing code.
You can use an HTML attribute tabIndex, where you can give a tab order to your element. Not only does it give the item an order, but when adding the attribute, it will be included in the tab navigation. Great! However, it is very annoying to manually add this to, say, 50 components, am I right?
You can also use tabIndex to disable the tab by giving it a -1 value. This is an easy fix for browsers who interpret the HTML weirdly or when the item is not always clickable.
Instead of manually changing all the components, risking creating bugs, or forgetting some pages, I made an Angular directive. You can probably do something similar in other frameworks as well.
The directive will look for all HTML items that contain a (click)="" attribute. Which would suggest the item is clickable. Moreover, it adds the correct role and tab index to the item. It’s a quick fix that can make your application more accessible.
import { Directive, HostBinding, HostListener } from '@angular/core';
@Directive({ selector: '*[click]:not([role]):not([tabindex]' })
export class ClickEqualsEnterDirective {
@HostBinding('attr.role') role = 'button';
@HostBinding('attr.tabindex') tabindex = '0';
@HostListener('keydown', ['$event']) onKeyDown(e: any) {
if (e.which === 13 || e.which === 32) {
e.preventDefault(); e.target.click();
}
}
}
Making your component library or more extensive web application accessible with the keyboard is not always easy. Making a directive that can look for items that use a (click) attribute was my way of making this a long-term solution without refactoring all the components.
Have you struggled with this issue? Let me know how you fixed it in your application!
Written by
Aagje Reynders
Want to know more?