Powrót do strony głównej

Dostępny DatePicker React WCAG 2.2

Artykuł opisuje tworzenie WCAG 2.2 AA DatePicker w React z poprawkami generacji AI. Omówione odstępstwa od APG, zarządzanie fokusem, aria-live assertive. Dla senior developerów.

WCAG DatePicker w React: od AI do ideału
Advertisement 728x90

Dostępny DatePicker w React zgodny z WCAG 2.2 AA

Zespół deweloperów oparł się na kodzie DatePicker wygenerowanym przez Claude'a według wzorca WAI-ARIA APG „Date Picker Dialog”. Pierwotny prompt zawierał wymagania WCAG 2.1/2.2 na poziomie AA: strukturę z inputem, aria-describedby, przyciskiem-triggerem, modal oknem role="dialog" i siatką tabeli kalendarza. Jednak surowa wersja ujawniła krytyczne wady w fokusie, nawigacji i dostępności.

AI stworzył podstawową nawigację klawiaturową (strzałki, Home/End, PageUp/Down, Enter/Spacja, Escape), roamingowy tabindex na gridcell, aria-live="polite" dla miesiąca. Ale testy na VoiceOver i NVDA pokazały: fokus nie trafiał na wybraną datę przy otwarciu, aria-live gromadził kolejkę komunikatów, okno dialogowe migało przy ponownym kliknięciu.

Odejścia od APG dla praktycznej dostępności

Specyfikacja APG nakazuje <td role="gridcell"> bez zagnieżdżonych przycisków, z ręcznym onClick/onKeyDown i tabindex. Praktyka wykazała zalety <button> wewnątrz <td>:

Google AdInline article slot
  • Natywna obsługa fokusu, Enter/Spacja bez dodatkowego kodu.
  • Automatyczna semantyka dla czytników ekranu.
  • Obsługa disabled bez aria-disabled i preventDefault.
  • Stabilne zdarzenia click z myszy/klawiatury.

To świadome odejście: specyfikacja to wskazówka, ale realne testy na urządzeniach mają priorytet. Kontrast ≥4.5:1, CSS Modules, natywny Date i Intl do formatowania — bez zewnętrznych zależności poza React/TypeScript.

Naprawa błędów funkcjonalnych i UX

Surowy kod nie kompilował się: brak index.html, błędy TypeScript. Po poprawkach wyszły na jaw:

Błędy funkcjonalne:

Google AdInline article slot
  • Data poza minDate/maxDate przenosiła na inny miesiąc zamiast pokazywać wyłączone komórki.
  • Niemożliwe wyczyszczenie inputu.

Problemy wizualne:

  • Brak stylu fokusu na komórkach.
  • Nierówne rozmiary td.

Dostępność:

  • Brak fokusu na dacie przy otwarciu — czytnik ekranu milczy.
  • aria-live="polite" na nagłówku miesiąca: kolejka komunikatów przy szybkim przełączaniu.
  • Blur+click na triggerze powodował migotanie okna.

Poprawki:

Google AdInline article slot
  • Fokus przy otwarciu na value lub dziś, czytnik odczytuje kontekst (dzień tygodnia, data, miesiąc, rok).
  • aria-live="assertive" w oddzielnym ukrytym regionie dla natychmiastowego ogłoszenia miesiąca.
  • Po wyborze — fokus na trigger z zaktualizowanym aria-label.
  • Pokaz miesiąca value nawet z wyłączonymi dniami.
  • Usunięte OK/Anuluj: Enter potwierdza, Esc zamyka.

Struktura komponentu i nawigacja klawiaturowa

Props: value (Date | null), onChange, minDate?, maxDate?, disabledDates?, locale?.

Kluczowe ARIA:

  • Input: aria-describedby dla formatu, readonly.
  • Trigger: dynamiczny aria-label ("Wybrano: DD.MM.RRRR" lub "Wybierz datę").
  • Dialog: role="dialog", aria-modal="true", pułapka fokusu.
  • Grid: table role="grid", td z button role="gridcell", aria-selected na value, aria-disabled na niedostępnych.
  • Nagłówek miesiąca: aria-live="assertive" w polite-regionie.

Nawigacja:

  • Strzałki: sąsiednie dni.
  • Home/End: pierwszy/ostatni dzień miesiąca.
  • PageUp/Down: ±1 miesiąc.
  • Shift+PageUp/Down: ±1 rok.
  • Enter/Spacja: wybór.
  • Escape: zamknięcie.

Co najważniejsze

  • AI przyspiesza szkielet (ARIA, nawigacja), ale wymaga ręcznych testów czytnikami ekranu.
  • <button> w <td> jest pewniejszy niż czysty gridcell w realnych przeglądarkach+czytnikach.
  • aria-live="assertive" dla nawigacji po miesiącach zapobiega kolejce.
  • Zarządzanie fokusem: otwarcie na value/dziś, powrót na trigger.
  • Minimalny stos: React + TS, bez bibliotek.

Komponent gotowy do produkcji jako single-date picker, z otwartym kodem do dalszego rozwoju (lata, zakresy).

— Editorial Team

Advertisement 728x90

Czytaj dalej