Pojęcia

Focus trap

Wzorzec, który utrzymuje fokus klawiatury wewnątrz otwartego okna modalnego — zapobiega wyjściu Tab z powrotem do dokumentu i przywraca fokus do elementu wyzwalającego po zamknięciu okna.

Focus trap (pułapka focusu) to celowe ograniczenie nawigacji klawiaturowej: gdy otwarte jest okno modalne, klawisz Tab krąży wyłącznie między elementami aktywnymi wewnątrz tego okna. Shift+Tab działa w odwrotnym kierunku. Użytkownik nie może użyć Tab, by wrócić do (wizualnie zablokowanej) strony za modalem, dopóki go jawnie nie zamknie.

Utrzymywanie focusu jest wymagane w dostępnych oknach modalnych. Bez niego użytkownicy klawiatury i czytników ekranu trafiają na niewidoczną treść strony, której ani nie widzą, ani nie mogą opuścić.

Dlaczego to konieczne

Okno modalne jest wizualnie prezentowane jako warstwa nad stroną. Intencja jest jednoznaczna: użytkownik ma pracować z modalem, aż skończy, a następnie wrócić do strony. Dla użytkowników myszy jest to intuicyjne: kliknięcie poza modalem nic nie robi (lub go zamyka); kliknięcie wewnątrz dosięga kontrolek modalu.

Bez focus trap użytkownicy klawiatury otrzymują niespójne doświadczenie:

  1. Otwiera się modal. Fokus przenosi się (lub powinien się przenieść) do pierwszego aktywnego elementu wewnątrz.
  2. Użytkownik naciska Tab. Fokus przechodzi do kolejnego aktywnego elementu w modalu.
  3. Użytkownik dalej naciska Tab. Fokus osiąga w końcu ostatni aktywny element w modalu.
  4. Jeszcze jeden Tab. Bez pułapki fokus skacze do kolejnego aktywnego elementu w dokumencie — gdzieś za modalem, niewidocznego dla użytkownika.

Jedynym sygnałem, że tak się stało, jest zniknięcie wskaźnika focusu z modalu. Użytkownik nie ma pojęcia, gdzie jest jego fokus.

Pełny wzorzec dla modalu

Kompletny dostępny modal zawiera:

  1. Fokus przenosi się do modalu przy jego otwarciu — zazwyczaj do pierwszego aktywnego elementu lub do nagłówka modalu (jeśli nagłówek ma tabindex="-1" dla programowego focusu).
  2. Fokus jest uwięziony wewnątrz modalu: Tab od ostatniego elementu wraca do pierwszego; Shift+Tab od pierwszego wraca do ostatniego.
  3. Escape zamyka modal i przywraca fokus do elementu wyzwalającego, który go otworzył (nie do body dokumentu).
  4. Kliknięcie poza modalem zamyka go — zachowanie opcjonalne; nie każdy modal tak robi, ale jeśli twój to robi, fokus musi pozostać uwięziony podczas otwarcia.
  5. role="dialog" wraz z aria-modal="true" na elemencie modalu, z aria-labelledby wskazującym na jego nagłówek.

Implementacje

Najczęściej cytowaną biblioteką jest focus-trap (npm: focus-trap, focus-trap-react, focus-trap-vue) — mała, bez zależności, obsługuje wszystkie przypadki brzegowe (pomija niewidoczne elementy, integruje się z inert, przywraca fokus przy zamknięciu).

Nowoczesnym prymitywem przeglądarki jest <dialog> z dialog.showModal(), który automatycznie utrzymuje fokus i obsługuje Escape. Wsparcie przeglądarek jest już wystarczająco szerokie, by używać tego jako linii bazowej.

Antywzorzec: „pułapka, która nie zwalnia”

Focus trap musi zwolnić fokus przy zamknięciu modalu. Najczęstszy błąd implementacyjny to zapomnienie o przywróceniu focusu do oryginalnego elementu wyzwalającego — fokus trafia wtedy na body dokumentu, co czytniki ekranu ogłaszają jako ciszę. Użytkownik zostaje „upuszczony w ciemność” i musi od nowa nawigować Tab od początku strony.