Tailwind CSS Accessibility Patterns (WCAG 2.2 - 2025/2026) WCAG 2.2 Overview (Current Standard)
WCAG 2.2 was released October 2023 and is the current W3C standard. Key additions relevant to Tailwind:
2.5.8 Target Size (Level AA): 24x24 CSS pixels minimum, 44x44 recommended 2.4.11 Focus Not Obscured: Focus indicators must be visible 2.4.13 Focus Appearance: Enhanced focus indicator requirements 3.3.7 Redundant Entry: Don't require re-entering information 3.2.6 Consistent Help: Help mechanisms in consistent locations Focus Management Focus Ring Utilities
@layer components { .focus-ring { @apply focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:ring-offset-2; }
.focus-ring-inset { @apply focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:ring-inset; } }
Skip Links
<a href="#main-content" class=" sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:bg-white focus:px-4 focus:py-2 focus:rounded-md focus:shadow-lg focus:ring-2 focus:ring-brand-500 "
Skip to main content
Focus Trap Pattern
Modal Title
Modal content
Screen Reader Utilities Visually Hidden Content
Additional context for screen readers
Announcing Dynamic Content
Color Contrast High Contrast Patterns
4.5:1 contrast ratio
May not meet WCAG AA (3:1 min for large text)
Large text - 3:1 ratio OK
Dark Mode Contrast
High contrast text
Secondary text with adequate contrast
⚠️ May have contrast issues in dark mode
Focus Indicator Contrast @theme { / High contrast focus ring / --color-focus: oklch(0.55 0.25 250); --color-focus-offset: oklch(1 0 0); }
Motion and Animation Reduced Motion
Safe Animation Patterns @layer components { / Animations that respect reduced motion / .animate-fade-in { @apply animate-in fade-in duration-300; @apply motion-reduce:animate-none motion-reduce:opacity-100; }
.animate-slide-up { @apply animate-in slide-in-from-bottom-4 duration-300; @apply motion-reduce:animate-none motion-reduce:translate-y-0; } }
Pause Animation on Hover
Form Accessibility Accessible Form Fields
We'll never share your email
Error States
Error: Password must be at least 8 characters
Form Validation Feedback / Style based on aria-invalid attribute / @custom-variant aria-invalid (&[aria-invalid="true"]);
Interactive Components Accessible Buttons
<button type="submit" aria-busy="true" aria-disabled="true" class=" relative aria-busy:cursor-wait aria-disabled:opacity-50 aria-disabled:cursor-not-allowed "
Submit Loading...
<button type="button" aria-label="Close dialog" class="rounded-full p-2 hover:bg-gray-100 focus-ring"
<button type="button" aria-pressed="false" class=" px-4 py-2 rounded-lg border aria-pressed:bg-brand-500 aria-pressed:text-white aria-pressed:border-brand-500 "
Toggle feature Feature
Accessible Dropdowns
Accessible Tabs
Touch Targets (WCAG 2.2 - Critical for 2025/2026) WCAG 2.2 Target Size Requirements Level Requirement Tailwind Class AA (2.5.8) 24x24 CSS pixels minimum min-h-6 min-w-6 Recommended 44x44 CSS pixels min-h-11 min-w-11 AAA (2.5.5) 44x44 CSS pixels min-h-11 min-w-11 Optimal 48x48 CSS pixels min-h-12 min-w-12
Platform guidelines comparison:
Apple iOS: 44x44 points minimum Google Android: 48x48 dp minimum Microsoft Fluent: 44x44 pixels minimum Minimum Touch Target Size
Extend Touch Target Beyond Visible Element
Card Title
Description text
View detailsSpacing Between Interactive Elements
WCAG 2.2 requires 24px spacing OR targets must be 24px minimum:
Touch Target Exceptions (WCAG 2.2)
Targets can be smaller than 24x24 if:
Inline text links within sentences Browser-provided controls (scrollbars) Size is essential to information A larger equivalent target exists on same page Text Accessibility Readable Text
Long form content with comfortable line height
Content with optimal line length (45-75 characters)
Paragraph 1
Paragraph 2
Text Resizing
Scales with user's font size preferences
⚠️ Won't scale with browser zoom
Semantic HTML with Tailwind Landmark Regions
Page Title
Section Title
Content...
Heading Hierarchy
Main Title (H1)
Section (H2)
Subsection (H3)
Content...
Testing Accessibility Browser DevTools Checklist Color contrast: Use contrast checker Focus order: Tab through the page Zoom: Test at 200% zoom Reduced motion: Enable in OS settings Automated Testing // axe-core integration import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
test('component is accessible', async () => {
const { container } = render(
Best Practices Summary (WCAG 2.2 - 2025/2026) Pattern Implementation WCAG Level Focus visible focus-visible:ring-2 focus-visible:ring-offset-2 2.4.7 (AA) Screen reader only sr-only 1.3.1 (A) Skip links sr-only focus:not-sr-only focus:absolute 2.4.1 (A) Reduced motion motion-reduce:animate-none motion-reduce:transition-none 2.3.3 (AAA) Touch targets (min) min-h-6 min-w-6 (24px) 2.5.8 (AA) Touch targets (rec) min-h-11 min-w-11 (44px) 2.5.5 (AAA) Touch spacing gap-3 (12px minimum between targets) 2.5.8 (AA) Text contrast 4.5:1 for normal, 3:1 for large text 1.4.3 (AA) Form errors aria-invalid="true" + role="alert" 3.3.1 (A) Focus not obscured Avoid z-index covering focused elements 2.4.11 (AA) Quick Reference: Touch-Friendly Component
<button type="button" class=" / Touch target size (44px minimum) / min-h-11 min-w-11 px-4 py-2.5
/* Typography */
text-sm md:text-base font-medium
/* Colors with sufficient contrast */
bg-blue-600 text-white
hover:bg-blue-700
/* Focus indicator (visible, not obscured) */
focus:outline-none
focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2
/* Shape */
rounded-lg
/* Disabled state */
disabled:opacity-50 disabled:cursor-not-allowed
/* Respect motion preferences */
transition-colors motion-reduce:transition-none
"
Button Text