Barrierefreiheit

Alle Picker-Komponenten werden mit integrierter Unterstützung für Barrierefreiheit ausgeliefert. Tastaturnavigation, ARIA-Attribute und Fokusverwaltung funktionieren standardmäßig in jeder Variante – Styled, Tailwind v3/v4 und Headless.

Für die Standardnutzung ist keine zusätzliche Konfiguration erforderlich. Diese Seite dokumentiert, was enthalten ist, damit Sie die Muster in benutzerdefinierten UIs prüfen, erweitern oder replizieren können.

Tastaturnavigation

Kalender-Picker

TasteAktion
ArrowLeftFokus auf den vorherigen Tag verschieben
ArrowRightFokus auf den nächsten Tag verschieben
ArrowUpFokus auf die vorherige Woche verschieben (gleicher Wochentag)
ArrowDownFokus auf die nächste Woche verschieben (gleicher Wochentag)
Enter / SpaceFokussierten Tag auswählen
EscapeÄnderungen abbrechen und Popup schließen
TabZum nächsten fokussierbaren Element wechseln (Browser-Standard)

Überspringen deaktivierter Daten: Bei der Navigation mit den Pfeiltasten werden deaktivierte Daten automatisch übersprungen. Der Picker sucht bis zu 365 Tage in Bewegungsrichtung, um das nächste aktivierte Datum zu finden.

Automatisches Monats-Scrollen: Wenn der Tastaturfokus auf einen Tag in einem anderen Monat wechselt, wird die Kalenderansicht aktualisiert, um diesen Monat anzuzeigen.

Zeitauswahl

TasteAktion
EscapeÄnderungen abbrechen und Popup schließen

Die Zeitauswahl verwendet eine Scrollrad-Benutzeroberfläche mit Klick-/Touch-Interaktion. Die Scroll-Spalten verwenden scroll-snap für eine präzise Wertauswahl.

ARIA-Attribute

Jedes interaktive Element verfügt über entsprechende ARIA-Rollen und -Attribute:

ElementAttributWert
Popup-Containerrole"dialog"
Inline-Containerrole"group"
Containeraria-labelPlatzhaltertext aus der Locale
Containeraria-activedescendantID der aktuell fokussierten Tageszelle

Auslöser-Schaltfläche

AttributWert
aria-expandedtrue, wenn das Popup geöffnet ist
aria-haspopup"dialog"

Kalenderraster

ElementAttributWert
Raster-Wrapperrole"grid"
Wochenzeilerole"row"
Wochentag-Kopfzeilerole"columnheader"
Tageszellerole"gridcell"
Tageszellearia-selectedtrue, wenn ausgewählt
Tageszellearia-current"date", wenn die Zelle heute ist
Tageszellearia-labelFormatierter Datumsstring (z.B. "2026-03-04")
TageszelledisabledBei deaktivierten Daten gesetzt (natives HTML-Attribut)
ElementAttributWert
Schaltfläche für vorherigen Monataria-label"Vorheriger Monat" (aus locale.prevMonthLabel)
Schaltfläche für nächsten Monataria-label"Nächster Monat" (aus locale.nextMonthLabel)
Monats-Dropdownaria-label"Monat auswählen" (aus locale.selectMonthLabel)
Jahres-Dropdownaria-label"Jahr auswählen" (aus locale.selectYearLabel)

Zeitspalten

ElementAttributWert
Stundenspalterole"listbox"
Stundenspaltearia-orientation"vertical"
Stundenspaltearia-label"Stunden" (aus locale.hourLabel)
Minutenspalterole"listbox"
Minutenspaltearia-orientation"vertical"
Minutenspaltearia-label"Minuten" (aus locale.minuteLabel)
Sekundenspalterole"listbox"
Sekundenspaltearia-orientation"vertical"
Sekundenspaltearia-label"Sekunden" (aus locale.secondLabel)
Zeitelementrole"option" (Padding-Elemente: "presentation")
Zeitelementaria-selectedtrue, wenn das Element der aktuelle Wert ist
Periodenumschalteraria-labelAktuelle Periode + ”, AM/PM umschalten”
Löschen-Schaltflächearia-label"Löschen" (aus locale.clear)

Alle Beschriftungsstrings sind über das Locale-System anpassbar.

Fokusverwaltung

Roving Tabindex

Das Kalenderraster verwendet das Roving-Tabindex-Muster:

  • Nur die aktuell fokussierte Tageszelle hat tabIndex={0} (per Tab erreichbar).
  • Alle anderen Tageszellen haben tabIndex={-1} (nicht per Tab erreichbar, aber über Pfeiltasten fokussierbar).
  • Das bedeutet, Tab verschiebt den Fokus aus dem Kalenderraster (zum nächsten Steuerelement), und die Pfeiltasten verschieben den Fokus innerhalb des Rasters.

Der Popup-Modus verwendet FloatingFocusManager von @floating-ui/react, um:

  • Den Fokus innerhalb des Popups zu halten, während es geöffnet ist.
  • Den Fokus auf die Auslöser-Schaltfläche zurückzugeben, wenn das Popup schließt.
  • Das Tabben aus dem Popup zu Hintergrundinhalten zu verhindern.

Native Elemente

Die Monats- und Jahresauswahl verwenden native <select>-Elemente, die von Natur aus per Tastatur zugänglich sind. Tageszellen verwenden native <button>-Elemente mit entsprechenden deaktivierten Zuständen.

WCAG 2.1-Konformität

Die folgenden WCAG 2.1-Erfolgskriterien werden erfüllt:

KriteriumLevelWie es erfüllt wird
1.3.1 Info und BeziehungenASemantisches HTML – <button>, <select>, grid/gridcell-Rollen
2.1.1 TastaturAAlle Funktionen per Tastatur erreichbar (Pfeiltasten, Enter, Escape)
2.4.3 Fokus-ReihenfolgeALogische Tab-Reihenfolge; Popup verwendet Fokus-Manager
2.4.7 Fokus sichtbarAA:focus-visible-Outline (2px solid primary) bei allen interaktiven Elementen
4.1.2 Name, Rolle, WertAAlle interaktiven Elemente haben zugängliche Namen über aria-label oder Textinhalt
📝 Note

Styling-Pakete (Styled, Tailwind v3/v4) enthalten standardmäßig sichtbare Fokusindikatoren. Wenn Sie eine benutzerdefinierte Benutzeroberfläche mit dem Headless-Paket erstellen, müssen Sie Ihre eigenen Fokus-Stile bereitstellen.

Headless: Erstellen barrierefreier benutzerdefinierter UIs

Wenn Sie das Headless-Paket direkt verwenden, stellen Sie sicher, dass Ihre benutzerdefinierte UI Folgendes enthält:

1. Tastatur-Handler anwenden

Übergeben Sie handleKeyDown an Ihren Popup-Container, damit die Navigation mit den Pfeiltasten funktioniert:

const { handleKeyDown, ... } = useDatePicker({ value, onChange });
<div onKeyDown={handleKeyDown}>
{/* Kalenderraster */}
</div>

2. Korrekten tabIndex für Tageszellen festlegen

Verwenden Sie das isFocused-Flag von getDayProps():

const dayProps = getDayProps(date);
<button
role="gridcell"
tabIndex={dayProps.isFocused ? 0 : -1}
aria-selected={dayProps.isSelected}
aria-current={dayProps.isToday ? "date" : undefined}
aria-label={locale.formatDate(date)}
>
{dayProps.day}
</button>;

3. ARIA-Rollen zum Raster hinzufügen

<div role="grid" aria-label={locale.placeholder}>
<div role="row">
{locale.weekdays.map((wd) => (
<div key={wd} role="columnheader">
{wd}
</div>
))}
</div>
{calendar.weeks.map((week, i) => (
<div key={i} role="row">
{/* Tageszellen mit role="gridcell" */}
</div>
))}
</div>

Eine vollständige Anleitung finden Sie unter Benutzerdefinierte UI erstellen.