$npx -y skills add vibeeval/vibecosystem --skill accessibility-patternsWCAG 2.2 AA compliance, ARIA patterns, keyboard navigation, screen reader optimization
| 1 | # Accessibility Patterns |
| 2 | |
| 3 | ## WCAG 2.2 AA Requirements |
| 4 | |
| 5 | ### Perceivable |
| 6 | |
| 7 | | Kriter | Kural | Kontrol | |
| 8 | |--------|-------|---------| |
| 9 | | 1.1.1 | Non-text content alt text | `<img alt="description">` | |
| 10 | | 1.3.1 | Semantic HTML | Headings, landmarks, lists | |
| 11 | | 1.4.3 | Color contrast | 4.5:1 normal text, 3:1 large | |
| 12 | | 1.4.11 | UI component contrast | 3:1 borders, icons | |
| 13 | |
| 14 | ### Operable |
| 15 | |
| 16 | | Kriter | Kural | Kontrol | |
| 17 | |--------|-------|---------| |
| 18 | | 2.1.1 | Keyboard accessible | Tab, Enter, Space, Escape | |
| 19 | | 2.4.3 | Focus order | Logical tab sequence | |
| 20 | | 2.4.7 | Focus visible | Visible focus indicator | |
| 21 | | 2.5.8 | Target size | Min 24x24px (44x44px önerilir) | |
| 22 | |
| 23 | ### Understandable |
| 24 | |
| 25 | | Kriter | Kural | Kontrol | |
| 26 | |--------|-------|---------| |
| 27 | | 3.1.1 | Language of page | `<html lang="tr">` | |
| 28 | | 3.2.1 | On focus | No unexpected context change | |
| 29 | | 3.3.1 | Error identification | Clear error messages | |
| 30 | | 3.3.2 | Labels or instructions | Form labels visible | |
| 31 | |
| 32 | ## ARIA Patterns |
| 33 | |
| 34 | ```html |
| 35 | <!-- Dialog --> |
| 36 | <div role="dialog" aria-modal="true" aria-labelledby="title"> |
| 37 | <h2 id="title">Confirm</h2> |
| 38 | <button aria-label="Close dialog">×</button> |
| 39 | </div> |
| 40 | |
| 41 | <!-- Tabs --> |
| 42 | <div role="tablist"> |
| 43 | <button role="tab" aria-selected="true" aria-controls="panel1">Tab 1</button> |
| 44 | <button role="tab" aria-selected="false" aria-controls="panel2">Tab 2</button> |
| 45 | </div> |
| 46 | <div role="tabpanel" id="panel1">Content 1</div> |
| 47 | |
| 48 | <!-- Live region (dynamic updates) --> |
| 49 | <div aria-live="polite" aria-atomic="true"> |
| 50 | 3 new messages |
| 51 | </div> |
| 52 | ``` |
| 53 | |
| 54 | ## Keyboard Navigation |
| 55 | |
| 56 | ```typescript |
| 57 | // Focus trap (modal/dialog) |
| 58 | function useFocusTrap(ref: RefObject<HTMLElement>) { |
| 59 | useEffect(() => { |
| 60 | const focusable = ref.current?.querySelectorAll( |
| 61 | 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])' |
| 62 | ) |
| 63 | const first = focusable?.[0] as HTMLElement |
| 64 | const last = focusable?.[focusable.length - 1] as HTMLElement |
| 65 | |
| 66 | function handleKeyDown(e: KeyboardEvent) { |
| 67 | if (e.key !== 'Tab') return |
| 68 | if (e.shiftKey && document.activeElement === first) { |
| 69 | e.preventDefault(); last.focus() |
| 70 | } else if (!e.shiftKey && document.activeElement === last) { |
| 71 | e.preventDefault(); first.focus() |
| 72 | } |
| 73 | } |
| 74 | ref.current?.addEventListener('keydown', handleKeyDown) |
| 75 | first?.focus() |
| 76 | return () => ref.current?.removeEventListener('keydown', handleKeyDown) |
| 77 | }, [ref]) |
| 78 | } |
| 79 | ``` |
| 80 | |
| 81 | ## Skip Links |
| 82 | |
| 83 | ```html |
| 84 | <a href="#main-content" class="skip-link">Skip to main content</a> |
| 85 | <!-- ... navigation ... --> |
| 86 | <main id="main-content">...</main> |
| 87 | |
| 88 | <style> |
| 89 | .skip-link { |
| 90 | position: absolute; |
| 91 | top: -40px; |
| 92 | left: 0; |
| 93 | z-index: 100; |
| 94 | } |
| 95 | .skip-link:focus { top: 0; } |
| 96 | </style> |
| 97 | ``` |
| 98 | |
| 99 | ## Motion Preferences |
| 100 | |
| 101 | ```css |
| 102 | @media (prefers-reduced-motion: reduce) { |
| 103 | *, *::before, *::after { |
| 104 | animation-duration: 0.01ms !important; |
| 105 | transition-duration: 0.01ms !important; |
| 106 | } |
| 107 | } |
| 108 | ``` |
| 109 | |
| 110 | ## Testing |
| 111 | |
| 112 | ```bash |
| 113 | # axe-core (automated) |
| 114 | npx @axe-core/cli https://localhost:3000 |
| 115 | |
| 116 | # Lighthouse accessibility audit |
| 117 | lighthouse --only-categories=accessibility https://localhost:3000 |
| 118 | ``` |
| 119 | |
| 120 | ## Checklist |
| 121 | |
| 122 | - [ ] Semantic HTML (headings, landmarks, lists) |
| 123 | - [ ] Alt text on all images |
| 124 | - [ ] Color contrast 4.5:1 (text), 3:1 (UI) |
| 125 | - [ ] Keyboard navigable (tab order logical) |
| 126 | - [ ] Focus visible indicator |
| 127 | - [ ] Skip link to main content |
| 128 | - [ ] Form labels and error messages |
| 129 | - [ ] ARIA roles where needed |
| 130 | - [ ] prefers-reduced-motion respected |
| 131 | - [ ] axe-core test pass |
| 132 | |
| 133 | ## Anti-Patterns |
| 134 | |
| 135 | - `<div onclick>` instead of `<button>` |
| 136 | - Color-only information (add icon/text) |
| 137 | - Auto-playing video/audio |
| 138 | - Removing focus outline without replacement |
| 139 | - Using ARIA when native HTML suffices |