Wil je een toegankelijk dialoogvenster maken? In dit artikel leg ik uit welke stappen je moet nemen volgens WCAG 2.2.
Als ontwikkelaar wil je dialoogvensters maken die iedereen kan gebruiken. Met de juiste aria-attributen en door kleine aanpassingen in de toetsenbordbediening toe te passen, zorg je voor een logisch en toegankelijk dialoogvenster.
Wat is een dialoogvenster?
Een dialoogvenster is een interface-element dat bovenop de hoofdinhoud verschijnt. Het vraagt de aandacht van de gebruiker en vereist een actie voordat je verder kan.
Structuur opbouwen
Het openen van een dialoogvenster gaat met een knop:
<button id="open-dialog">Open dialoogvenster</button>
Gebruik een <div>
-element met role='dialog'
als container voor het dialoogvenster:
<div
role="dialog"
aria-modal="true"
aria-labelledby="dialog-title"
aria-describedby="dialog-description"
class="modal"
id="demo-dialog">
In deze code zie je verschillende ARIA-attributen. Ik leg ze even uit:
role="dialog"
: Vertelt hulptechnologieën dat dit een dialoogvenster is.aria-modal="true"
: Geeft aan dat de rest van de pagina niet kan worden gebruikt als dit venster open is.aria-labelledby="dialog-title"
: Koppelt de titel aan het dialoogvenster.aria-describedby="dialog-description"
: Koppelt de beschrijving aan het dialoogvenster.
In de container staat de inhoud van het dialoogvenster. De ARIA-attributen van de container verwijzen naar het ID van elementen van deze inhoud:
<div class="modal-content">
<!-- Sluiten knop -->
<button class="close-button" aria-label="Sluiten">×</button>
<!-- Titel -->
<h2 id="dialog-title">Titel van dialoogvenster</h2>
<!-- Inhoud -->
<p id="dialog-description">Beschrijving van het doel van dit venster.</p>
<!-- Actie knoppen -->
<div class="modal-actions">
<button class="secondary-button">Annuleren</button>
<button class="primary-button">Bevestigen</button>
</div>
</div>
Interactie
Gebruik JavaScript om het dialoogvenster goed te laten werken:
Focusmanagement
Bij het openen van het dialoogvenster moet de focus automatisch naar een element binnen het venster gaan. Bij het sluiten keert de focus terug naar het element waarmee het venster werd geopend.
// Bij openen
openButton.addEventListener('click', function() {
openModal();
closeButton.focus(); // Focus op eerste element in het dialoogvenster
});
// Bij sluiten
function closeModal() {
modal.style.display = 'none';
openButton.focus(); // Focus terug naar knop die het dialoogvenster opende
}
Focus vasthouden
Gebruikers mogen niet buiten het dialoogvenster kunnen navigeren:
// Focus binnen het dialoogvenster houden
modal.addEventListener('keydown', function(event) {
// ESC-toets sluit het venster
if (event.key === 'Escape') {
closeModal();
}
// TAB-toets binnen het venster houden
if (event.key === 'Tab') {
// Alle focusbare elementen vinden
const focusableElements = modal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
// Als we achteruit tabben en bij het eerste element zijn
if (event.shiftKey && document.activeElement === firstElement) {
lastElement.focus();
event.preventDefault();
}
// Als we vooruit tabben en bij het laatste element zijn
else if (!event.shiftKey && document.activeElement === lastElement) {
firstElement.focus();
event.preventDefault();
}
}
});
Escape-toets
Gebruikers het dialoogvenster laten sluiten met de Escape-toets:
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape' && modal.style.display === 'block') {
closeModal();
}
});
Codevoorbeeld
HTML
<div
role="dialog"
aria-modal="true"
aria-labelledby="dialog-title"
aria-describedby="dialog-description"
class="modal"
id="demo-dialog">
<div class="modal-content">
<!-- Sluiten knop -->
<button class="close-button" aria-label="Sluiten">×</button>
<!-- Titel -->
<h2 id="dialog-title">Titel van dialoogvenster</h2>
<!-- Inhoud -->
<p id="dialog-description">Beschrijving van het doel van dit venster.</p>
<!-- Actie knoppen -->
<div class="modal-actions">
<button class="secondary-button">Annuleren</button>
<button class="primary-button">Bevestigen</button>
</div>
</div>
</div>
Javascript
// Elementen selecteren
const modal = document.querySelector('.modal');
const openButton = document.querySelector('.open-modal-button');
const closeButton = document.querySelector('.close-button');
const cancelButton = document.querySelector('.secondary-button');
const confirmButton = document.querySelector('.primary-button');
// Functie om het dialoogvenster te openen
function openModal() {
modal.style.display = 'block';
// Focus op de eerste knop in het venster
closeButton.focus();
// Bewaar de laatst gefocuste element voor als we sluiten
lastFocus = document.activeElement;
}
// Functie om het dialoogvenster te sluiten
function closeModal() {
modal.style.display = 'none';
// Terug naar waar de gebruiker was
lastFocus.focus();
}
// Event listeners
openButton.addEventListener('click', openModal);
closeButton.addEventListener('click', closeModal);
cancelButton.addEventListener('click', closeModal);
confirmButton.addEventListener('click', function() {
// Voer actie uit en sluit venster
closeModal();
});
// Focus binnen het dialoogvenster houden (focus trap)
modal.addEventListener('keydown', function(event) {
// ESC-toets sluit het venster
if (event.key === 'Escape') {
closeModal();
}
// TAB-toets binnen het venster houden
if (event.key === 'Tab') {
// Alle focusbare elementen vinden
const focusableElements = modal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
// Als we achteruit tabben en bij het eerste element zijn
if (event.shiftKey && document.activeElement === firstElement) {
lastElement.focus();
event.preventDefault();
}
// Als we vooruit tabben en bij het laatste element zijn
else if (!event.shiftKey && document.activeElement === lastElement) {
firstElement.focus();
event.preventDefault();
}
}
});
Demo
Toegankelijkheidskenmerken
- Toetsenbordbediening
- Focus wordt vastgehouden binnen het dialoogvenster.
- Focus keert terug naar het element dat focus had vóór het openen.
- Sluit het dialoogvenster met de Escape-toets.
- Schermlezers
- Dialoogvenster heeft een duidelijke label en beschrijving.
Conclusie
Het dialoogvenster voldoet zo aan de volgende succescriteria:
- 1.3.1 Info en relaties
- 2.1.1 Toetsenbord
- 2.1.2 Geen toetsenbordval
- 2.1.4 Sneltoetsen
- 2.4.3 Focus volgorde
- 2.4.6 Koppen en labels
- 2.4.7 Focus zichtbaar
- 4.1.2 Naam, rol, waarde
Let bij het toepassen van het dialoogvenster ook op de juiste kleuren voor:
- 1.4.3 Contrast (minimum)
- 1.4.11 Contrast van niet-tekstuele content
Wil je zeker weten dat jouw dialoogvenster toegankelijk is? Test deze dan zelf eens met een schermlezer en alleen met het toetsenbord.
Heb je vragen over deze implementatie? Laat het me weten!