-
Notifications
You must be signed in to change notification settings - Fork 280
Description
Was planning to move to this library as part of Drupal's suggestion for having good a11y support, but ran into this issue whilst testing.
The specification and examples for creating an accessible modal dialog is defined here: https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/examples/dialog/#ex_label
The main issues highlighted so far:
- When Tab is pressed, and the focus is on the last focusable element within the dialog, it should move focus back to the first focusable element in the dialog, rather than to an element that's below the dialog.
- Necessary
aria-
attributes are missing from the modal, e.g.role="dialog"
,aria-modal="true"
etc. - There should be visual feedback when the checkboxes and other elements are currently in focus, e.g. https://getbootstrap.com/docs/4.0/components/modal/#modal-components
Steps to reproduce
- Create a modal dialog for Klaro, and attempt to navigate entirely through the keyboard or a screenreader.
Current behavior
- Pressing tab will cause the user to focus out of the modal, which isn't accessible.
- Certain ARIA attributes are missing.
Expected behavior
Tabbing should be locked to just the focusable elements within the modal, stopping the user from accidentally tabbing to an element beneath the dialog.
The resource linked to above should provide resources as for how to best implement this feature.
However this piece of snippet I wrote may also be used to provide the necessary keyboard support until this is supported natively.
NB: My implementation directly focuses on keyboard events whilst theirs handles all scenarios where focus is placed on a foreign element whilst the modal is open:
function keyboardHandler(event) {
if (event.key === 'Tab' || event.keyCode === 9) {
const container = document.querySelector('#klaro');
if (!container) {
return;
}
// Get all focusable elements inside the container
const focusableElements = container.querySelectorAll('button, a[href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
// If Shift + Tab on the first focusable element, move focus to the last
if (event.shiftKey && document.activeElement === firstElement) {
event.preventDefault();
lastElement.focus();
}
else if (!event.shiftKey && document.activeElement === lastElement) {
// If we're Tabbing on the last focusable element, move focus back to the first
event.preventDefault();
firstElement.focus();
}
}
else if (event.key === 'Escape' || event.keyCode === 27) {
// Try clicking the close button.
const closeButton = document.querySelector('#klaro button.hide');
if (closeButton) {
closeButton.click();
}
}
}
window.addEventListener('keydown', keyboardHandler);