React / Accessibility / WCAG

    React Aria i dostępność (a11y)

    React Aria (Adobe headless hooks), AriaKit (composable primitives), WAI-ARIA patterns, jest-axe i testowanie screen reader — WCAG 2.1 w React.

    React Aria
    Adobe hooks
    AriaKit
    Composable
    jest-axe
    Auto testing
    WAI-ARIA
    ARIA spec

    6 bibliotek dostępności React — porównanie

    react-aria, AriaKit, Radix UI, jest-axe, Storybook a11y i Base UI — vendor, podejście i zastosowanie.

    Biblioteka Vendor Podejście Kiedy
    react-aria-components Adobe Headless components DatePicker, ColorPicker, kompleksowe componenty
    @ariakit/react Ariakit Composable primitives Menu, Dialog, Tabs — kompozycja
    @radix-ui/react-* WorkOS Headless primitives shadcn/ui, custom design systems
    jest-axe jest + axe-core Auto testing Unit testy a11y w Jest/Vitest
    @storybook/addon-a11y Storybook Component a11y testing Testy a11y per story w Storybook
    Base UI (@mui) MUI Headless primitives Alternatywa Radix, MUI ecosystem

    Często zadawane pytania

    Co to jest React Aria (Adobe) i jak pomaga z dostępnością?

    React Aria (Adobe): biblioteka hooks dla dostępności. Nie komponenty — hooki. Pełna ARIA 1.2 conformance. Keyboard navigation. Screen reader support. Focus management. Touch/pointer. Instalacja: npm install react-aria @react-aria/button @react-aria/dialog. Lub: npm install react-aria-components — nowe komponenty (stabilne od v1). react-aria-components: Wbudowane komponenty. Headless — pełna kontrola stylów. Button, Input, Select, ComboBox, Dialog, Modal, DatePicker, ColorPicker, Toast. Przykład Button: import {Button} from 'react-aria-components'. Button className='btn' onPress={handleClick}. Hooki API: useButton(props, ref) — button accessibility. {buttonProps} = useButton({onPress}, ref). Spread buttonProps na element. Dlaczego React Aria: ARIA patterns są skomplikowane. Każdy komponent ma unikalne wymagania. Screen readers (NVDA, VoiceOver) — różne zachowanie. Focus trapping w modals. Keyboard shortcuts. React Aria testowany na prawdziwych screen readerach. Live regions: status announcements. ARIA live. React Aria's toasts. Focus ring: useVisuallyHidden, useFocusRing. Widoczny fokus tylko dla keyboard. Nie dla mouse. :focus-visible CSS. Internationalization (react-intl): @react-aria/i18n. Lokalny format dat. RTL support (arabski, hebrajski). Bidirectional text. Adobe Spectrum (React Spectrum): pełny design system nad React Aria. Gotowe komponenty ze stylem. Spectrum design guidelines.

    AriaKit — alternatywa React Aria dla dostępnych komponentów?

    AriaKit (Reakit rebrand): headless accessible components. Composable — łącz prymitywy. CSR i SSR. TypeScript. Instalacja: npm install @ariakit/react. Komponenty: Button, Checkbox, Combobox, Dialog, Disclosure, Form, Hovercard, Menu, Popover, Radio, Select, Tab, Tooltip. Menu przykład: import {MenuButton, Menu, MenuItem} from '@ariakit/react'. MenuButton render='button'. Menu. MenuItem render={Link href='/profile'}. Menu zamyka się po wybore. Komposycja: render prop — swap wewnętrzny element. Integracja z react-router Link. Integracja z Next.js Link. Tooltip: Tooltip — wraps children. TooltipAnchor. TooltipProvider. Keyboard trigger. Brak na mobilnych (hover nie istnieje). Własne opóźnienie. Dialog i Drawers: Dialog — modal i non-modal. Backdrop. FocusTrap. Escape to close. AriaKit vs React Aria: AriaKit — prymitywy composable. React Aria — hooks-based. React Aria — bogatszy (ColorPicker, DatePicker). AriaKit — prostszy API. Oba: headless, testowane z screen readers. Radix UI (Primitives): headless accessible components. @radix-ui/react-dialog, @radix-ui/react-dropdown-menu. shadcn/ui — nad Radix UI. asChild pattern: Slot component. Przekazuje props do dziecka. Brak wrapping div. Base UI (MUI): nowa, headless. Zbliżone do Radix. Less mature. Park UI: nad Ark UI (Chakra). Headless + styled. Zagnieżdżone ARIA: aria-labelledby zamiast aria-label dla grup.

    WAI-ARIA patterns — dostępność komponentów React?

    WAI-ARIA Authoring Practices Guide (APG): oficjalny przewodnik ARIA. Każdy komponent ma pattern. Keyboard interactions spec. ARIA roles, states, properties. Button pattern: role='button'. Enter i Space = click. aria-pressed dla toggle. aria-disabled (nie disabled — focus zachowany). Dialog pattern: role='dialog'. aria-modal='true'. aria-labelledby heading. FocusTrap — Tab i Shift+Tab w modalu. Escape zamyka. Nie aria-hidden=true na aktywnym modalu. Combobox pattern: input + listbox. aria-haspopup='listbox'. aria-expanded. aria-activedescendant — wskazuje na opcję. Home/End navigacja. Tab tree: role='tree'. aria-expanded na gałęziach. Strzałki nawigacja. aria-selected. Tabs: role='tablist'. role='tab'. aria-selected='true'. role='tabpanel'. Keyboard: strzałki między tabami. Data tables: scope='col', scope='row'. caption. headers attr dla złożonych tabel. summary (deprecated). Focus management: useRef na pierwszy interaktywny element. focus() po otwarciu modala. Zwróć focus do triggera po zamknięciu. Live regions: role='status' — uprzejme ogłoszenia. role='alert' — pilne. aria-live='polite'. aria-live='assertive'. Brak nadużywania — denerwuje. Color contrast: WCAG AA: 4.5:1 (tekst normalny). 3:1 (tekst duży, UI). WCAG AAA: 7:1. Narzędzia: axe-core, Lighthouse, WAVE. Prefers-color-scheme: dark mode. Prefers-reduced-motion: brak animacji.

    Testowanie dostępności — axe-core, jest-axe i screen reader testing?

    axe-core: automatyczne testy dostępności. Deque Systems. Najpopularniejszy engine. jest-axe: jest + axe-core. import {axe, toHaveNoViolations} from 'jest-axe'. expect.extend(toHaveNoViolations). const results = await axe(container). expect(results).toHaveNoViolations(). Co wykrywa: brakujące alt text. Brak label na form. Kontrast kolorów. Brak lang na html. Aria roles. Puste linki. Storybook a11y addon: @storybook/addon-a11y. Automatyczne axe per story. A11y panel. Violations, warnings. CI: storybook test-runner + a11y. Playwright a11y: import {checkA11y} from 'axe-playwright'. await checkA11y(page). Dla E2E testów. Lighthouse CI: automatyczny Lighthouse. Accessibility score. lighthouse-ci w GitHub Actions. Manualne testowanie screen readerów: VoiceOver (macOS/iOS) — CMD+F5. NVDA (Windows) — darmowy, Chrome/Firefox. JAWS (Windows) — komercyjny, najpopularniejszy. TalkBack (Android). Orca (Linux). Jak testować: uruchom screen reader. Zamknij oczy. Nawiguj przez Tab. Sprawdź logiczną kolejność. Słuchaj announcementów. Sprawdź formularze. Sprawdź modal focus. Keyboard-only testing: odłącz mysz. Nawiguj tylko Tab, Strzałki, Enter, Escape. Sprawdź focus visibility. Sprawdź focus order. Brak focus traps (poza modalami). Kontrast: Color Contrast Analyzer (narzędzie). Chrome DevTools - accessibility panel. WCAG Color Contrast Checker - online. Polecane narzędzia: axe Browser Extension. WAVE Extension. Accessibility Insights (Microsoft). IBM Equal Access Checker.

    Implementacja dostępności w React — praktyczny przewodnik?

    Skip link: a href='#main' className='skip-link'. Omijaj nawigację dla keyboard. Widoczny przy focus. Przenosi fokus do main. Semantyczny HTML: header, nav, main, article, footer, aside, section. h1-h6 hierarchia. ul, ol, li. button zamiast div onClick. Nie div role='button' bez potrzeby. img alt='': opisowy alt text. Dekoracyjne: alt=''. Kompleksowe: aria-describedby. Formularze: label htmlFor='input-id'. lub label wrapping input. aria-required='true'. aria-invalid={!!error}. aria-describedby='error-id'. error-id span z komunikatem. Fokus: useFocusRing (React Aria). :focus-visible CSS. outline: 2px solid blue. Nie outline: none!. Animacje: useReducedMotion (Framer Motion). @media (prefers-reduced-motion). prefers-reduced-motion: reduce -> brak animacji. Kolory: nie kolor jedynym znacznikiem. Ikona + tekst + kolor. error: czerwony + ikona + tekst. Custom select: Radix Select lub React Aria Select. Nie native select z custom styling. Native select w CSS — trudny. Skip to content pattern. Landmark regions: header, nav, main, footer — automatyczne landmarks. role='search' dla formy wyszukiwania. role='banner' (header). role='contentinfo' (footer). Aria labels: aria-label='Close dialog'. aria-labelledby='heading-id'. aria-describedby='description-id'. Brak aria-label na elementy z visible text — powielenie. Loading state: aria-busy='true'. aria-live='polite'. Spinner — aria-label='Loading...'. Toast notifications: role='status'. Lub react-hot-toast (dostępny). Pozycja poza viewport nie przeszkadza. aria-atomic='true'.

    Czytaj dalej

    Powiązane artykuły

    Kontakt

    Skontaktuj się z nami

    Porozmawiajmy o Twoim projekcie. Bezpłatna wycena w ciągu 24 godzin.

    Wyślij zapytanie

    Bezpłatna wycena w 24h
    Bez zobowiązań
    Indywidualne podejście
    Ekspresowa realizacja

    Telefon

    +48 790 814 814

    Pon-Pt: 9:00 - 18:00

    Email

    adam@fotz.pl

    Odpowiadamy w ciągu 24h

    Adres

    Plac Wolności 16

    61-739 Poznań

    Godziny pracy

    Pon - Pt9:00 - 18:00
    Sob - NdzZamknięte

    Wolisz porozmawiać?

    Zadzwoń teraz i porozmawiaj z naszym specjalistą o Twoim projekcie.

    Zadzwoń teraz