Drawer Barrierefreiheit
Implementierte Verbesserungen
Die Drawer-Komponente wurde mit folgenden Barrierefreiheitsverbesserungen aktualisiert:
ARIA-Attribute
role="dialog"
- Definiert den Drawer als Dialogaria-modal="true"
- Zeigt an, dass der Dialog modal istaria-labelledby
- Verknüpft den Titel mit dem Draweraria-label
- Alternative Bezeichnung, wenn kein Titel vorhanden istaria-describedby
- Verknüpft eine detaillierte Beschreibung mit dem Drawer
Für den Schließen-Button:
aria-label="Schließen"
- Beschreibt die Funktion des Buttonsaria-hidden="true"
für dekorative Icons
Fokus-Management
- Focus-Trap zur Begrenzung des Fokus innerhalb des Drawers
- Automatischer Fokus auf den Schließen-Button beim Öffnen
- Rückgabe des Fokus zum auslösenden Element beim Schließen
- Speicherung des Elements, das vor dem Öffnen den Fokus hatte
- Sichtbare Fokus-Indikatoren für alle interaktiven Elemente
Tastaturnavigation
- Escape-Taste zum Schließen des Drawers
- Tab-Navigation durch alle interaktiven Elemente
- Zyklische Tab-Navigation innerhalb des Drawers (Focus-Trap)
Screenreader-Unterstützung
- Beschreibende Texte für den Drawer und seine Funktionen
- Versteckte Hilfstexte mit
sr-only
-Klassen - Korrekte Hierarchie von Überschriften
Beispiel-Implementierung
<div
ref={drawerRef}
id={uniqueId}
role="dialog"
aria-modal="true"
aria-labelledby={title ? titleId : undefined}
aria-label={!title ? ariaLabel || 'Drawer' : undefined}
aria-describedby={ariaDescription ? descriptionId : undefined}
tabIndex={-1}
>
{ariaDescription && (
<div id={descriptionId} className="sr-only">
{ariaDescription}
</div>
)}
{showHeader && (
<div className="header">
<h2 id={titleId}>
{title}
</h2>
<button
ref={closeButtonRef}
type="button"
onClick={onClose}
aria-label="Schließen"
>
<svg aria-hidden="true">
{/* Icon */}
</svg>
</button>
</div>
)}
<div className="content">
{children}
</div>
</div>
Focus-Trap Implementierung
// ESC-Taste zum Schließen und Focus-Trap
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (!isOpen) return;
// ESC-Taste zum Schließen
if (e.key === 'Escape') {
e.preventDefault();
onClose();
return;
}
// Tab-Taste für Focus-Trap
if (e.key === 'Tab') {
if (!firstFocusableRef.current || !lastFocusableRef.current) return;
// Shift+Tab: Wenn der Fokus auf dem ersten Element ist, gehe zum letzten Element
if (e.shiftKey && document.activeElement === firstFocusableRef.current) {
e.preventDefault();
lastFocusableRef.current.focus();
}
// Tab: Wenn der Fokus auf dem letzten Element ist, gehe zum ersten Element
else if (!e.shiftKey && document.activeElement === lastFocusableRef.current) {
e.preventDefault();
firstFocusableRef.current.focus();
}
}
};
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
}, [isOpen, onClose]);
Fokus-Rückgabe
// Setze den Fokus zurück, wenn der Drawer geschlossen wird
useEffect(() => {
if (!isOpen && previouslyFocusedElement) {
// Wenn eine ID oder ein Element zum Zurücksetzen des Fokus angegeben wurde, verwende dieses
if (returnFocusToId) {
const element = document.getElementById(returnFocusToId);
if (element) {
element.focus();
return;
}
}
if (returnFocusToElement) {
returnFocusToElement.focus();
return;
}
// Sonst setze den Fokus auf das Element, das vorher den Fokus hatte
previouslyFocusedElement.focus();
}
}, [isOpen, previouslyFocusedElement, returnFocusToId, returnFocusToElement]);
Barrierefreiheitstests
Die Drawer-Komponente wurde mit folgenden Tests auf Barrierefreiheit geprüft:
- Automatisierte Tests mit jest-axe zur Überprüfung der ARIA-Attribute
- Tastaturnavigation zur Sicherstellung der vollständigen Bedienbarkeit ohne Maus
- Screenreader-Tests zur Überprüfung der korrekten Ankündigungen
- Fokus-Management-Tests zur Sicherstellung der korrekten Fokusreihenfolge
Bekannte Einschränkungen
- Bei sehr komplexen Inhalten im Drawer kann die Tastaturnavigation umständlich sein
- Bei mehreren verschachtelten Drawern kann das Fokus-Management komplex werden