--- name: kb-framework-accessibility description: Reference data, not a reviewer. Framework-specific accessibility patterns and fix templates for React, Vue, Angular, Svelte, Next.js, and Tailwind CSS. license: MIT disable-model-invocation: true user-invocable: false metadata: tier: reference domain: cross-cutting output: none effort: low title: Framework Accessibility --- ## Framework-Specific Accessibility Patterns ## React / Next.js ### Common Pitfalls Each pattern, with its issue and fix. | Pattern | Issue | Fix | |---------|-------|-----| | `onClick` on `
` | Not keyboard accessible | Use ` // Bad: image without alt in Next.js // Good: image with alt Team collaborating in a modern office // Bad: no focus management on route change useEffect(() => { // nothing }, [location]); // Good: focus management on route change useEffect(() => { const mainContent = document.getElementById('main-content'); if (mainContent) { mainContent.focus(); mainContent.scrollIntoView(); } }, [location]); // Bad: link opening new tab Resource // Good: link with new tab warning Resource (opens in new tab) ``` ## Vue ### Common Pitfalls Each pattern, with its issue and fix. | Pattern | Issue | Fix | |---------|-------|-----| | `v-html` with user content | May inject inaccessible markup | Sanitize and audit injected HTML | | `v-if` on live regions | Removes element from DOM, breaks announcements | Use `v-show` for live regions instead | | `` without focus | Focus lost when content transitions | Manage focus in `@after-enter` hook | | `` to body | Content outside app landmark tree | Add landmark roles to teleported content | ### Fix Templates ```vue
{{ message }}
{{ message }}
``` ## Angular ### Common Pitfalls Each pattern, with its issue and fix. | Pattern | Issue | Fix | |---------|-------|-----| | `[aria-label]` binding | Invalid - ARIA is not a property | Use `[attr.aria-label]` | | `*ngFor` without `trackBy` | Focus loss on list re-render | Add `trackBy` function | | No `LiveAnnouncer` | Route changes not announced | Inject `LiveAnnouncer` and announce navigation | | `OnPush` + live regions | Change detection may not trigger | Use `ChangeDetectorRef.markForCheck()` | ### Fix Templates ```typescript // Bad: ARIA binding // Good: ARIA attribute binding // Bad: ngFor without trackBy
  • {{ item.name }}
  • // Good: ngFor with trackBy
  • {{ item.name }}
  • // Route change announcements constructor(private liveAnnouncer: LiveAnnouncer, private router: Router) { this.router.events.pipe( filter(event => event instanceof NavigationEnd) ).subscribe((event: NavigationEnd) => { this.liveAnnouncer.announce(`Navigated to ${this.getPageTitle()}`); }); } ``` ## Svelte ### Common Pitfalls Each pattern, with its issue and fix. | Pattern | Issue | Fix | |---------|-------|-----| | `{#if}` without focus management | Focus lost when content appears | Use `use:action` to focus new content | | `transition:` without motion check | Animations play regardless of user preference | Add `prefers-reduced-motion` check | | `on:click` on non-interactive | Not keyboard accessible | Use `
    Content
    Content
    ``` ## Tailwind CSS ### Common Pitfalls Each pattern, with its issue and fix. | Pattern | Issue | Fix | |---------|-------|-----| | `outline-none` | Removes focus indicator | Pair with `ring-2 ring-offset-2 focus-visible:ring-blue-500` | | `text-gray-400` on `bg-white` | Fails 4.5:1 contrast | Use `text-gray-600` or darker | | No `motion-reduce:` variant | Animations ignore user preference | Add `motion-reduce:transition-none` | | Missing `focus:` styles | No visible focus indicator | Add `focus:ring-2 focus:ring-blue-500` | | `sr-only` missing | Screen reader text not available | Add `description` | ### Contrast-Safe Tailwind Pairs Each background, with its minimum text and ratio. | Background | Minimum Text | Ratio | |-----------|-------------|-------| | `bg-white` | `text-gray-600` | 4.55:1 | | `bg-white` | `text-gray-700` | 6.62:1 | | `bg-gray-50` | `text-gray-700` | 6.29:1 | | `bg-gray-900` | `text-gray-300` | 5.92:1 | | `bg-blue-600` | `text-white` | 5.23:1 | | `bg-red-600` | `text-white` | 4.54:1 | | `bg-green-700` | `text-white` | 4.58:1 | ### Fix Templates ```html

    Important information

    Important information

    Card
    Card
    ```