This guide explains the accessibility patterns used across every component in the library. Follow these patterns when customizing components to maintain WCAG 2.1 AA compliance.
Every component uses the correct HTML element for its purpose. This provides baseline accessibility that works even without JavaScript:
Anti-pattern to avoid: Using Every interactive component works with the keyboard: Visible Focus Indicators: All focusable elements have a visible focus ring using Tailwind's Focus Trapping in Modals: When a modal opens, Tab should only cycle through elements inside the modal, not escape to the page behind it: Focus Restoration: When a modal or slide-over closes, focus should return to the element that opened it: Minimum Contrast Ratios (WCAG AA): Never rely on color alone to convey information: All animations respect the user's motion preference: Or per-component with Tailwind: Run these on every build: 1. axe-core — Catches ~30% of accessibility issues 2. eslint-plugin-jsx-a11y — Catches issues at lint time 1. Tab through the page — Can you reach every interactive element? Is the tab order logical? 2. Use a screen reader — VoiceOver (Mac), NVDA (Windows), or JAWS. Does it announce elements correctly? 3. Zoom to 200% — Does the layout still work? Is text readable? 4. Turn off CSS — Does the content still make sense? 5. Use keyboard only — Can you complete every task without a mouse? 6. Check color contrast — Use the browser's DevTools accessibility inspector Part of Frontend Developer Pro Get the full Tailwind Component Library and unlock everything. Get the complete guide with every chapter unlocked, including code samples, diagrams, and best practices. Access all interactive tools with complete data, all workload profiles, and the full scenario library. Downloadable source code, configuration files, and working examples from every chapter. Free updates for life. Every new chapter, tool, and improvement included.. A div has no keyboard support, no screen reader announcement, and no built-in focus styling.
2. Keyboard Navigation
Component Tab Enter/Space Escape Arrow Keys Buttons Focus Activate - - Text inputs Focus Submit form - Move cursor Checkboxes Focus Toggle - - Radio groups Focus group Select - Next/previous option Toggle switch Focus Toggle - - Tabs Focus tab list Select tab - Next/previous tab Modals Focus first element Activate focused element Close modal - Dropdowns Focus trigger Open/close Close Navigate items Command palette Focus search Select item Close Navigate items 3. Focus Management
focus-visible:ring-2:// We use focus-visible instead of focus so the ring only appears
// during keyboard navigation, not mouse clicks
className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500"// The Modal component traps focus by intercepting Tab and Shift+Tab
// and wrapping around to the first/last focusable element
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key !== "Tab") return;
const focusable = modalRef.current.querySelectorAll<HTMLElement>(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
// ... wrap focus between first and last
};const previousFocusRef = useRef<HTMLElement | null>(null);
useEffect(() => {
if (isOpen) {
previousFocusRef.current = document.activeElement as HTMLElement;
} else {
previousFocusRef.current?.focus();
}
}, [isOpen]);4. ARIA Attributes Reference
Attribute Where Used Purpose aria-labelIcon-only buttons Provides accessible name aria-labelledbyModals, sections Links element to its heading aria-describedbyForm inputs Links to error/helper text aria-requiredRequired inputs Announces "required" aria-invalidInputs with errors Announces "invalid entry" aria-expandedDropdowns, accordions Announces open/closed state aria-controlsTabs, accordions Links trigger to content aria-selectedTabs, list items Announces selected state aria-current="page"Navigation links Announces current page aria-sortTable headers Announces sort direction aria-live="polite"Toast/alerts Announces dynamic content aria-modal="true"Modals Marks as modal dialog role="alert"Error messages Immediate announcement role="status"Success messages Polite announcement role="switch"Toggle switches Announces as switch 5. Color and Contrast
Text Type Required Ratio Our Default Normal text (< 18px) 4.5:1 5.1:1+ Large text (>= 18px) 3:1 4.2:1+ UI components (borders, icons) 3:1 3.5:1+ // Bad: Color is the only indicator
<span className="text-red-500">Error</span>
// Good: Icon + color + text
<span className="text-danger-600">
<ErrorIcon /> Error: Field is required
</span>6. Motion and Animation
/* In your global CSS */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}className="motion-safe:animate-fade-in motion-reduce:animate-none"Testing Accessibility
Automated Testing
npm install -D @axe-core/react npm install -D eslint-plugin-jsx-a11yManual Testing Checklist
Screen Reader Testing Tips
Platform Screen Reader Toggle macOS VoiceOver Cmd + F5 Windows NVDA Free download from nvaccess.org Windows Narrator Win + Ctrl + Enter Chrome ChromeVox Extension Customization Guide
Accessibility Guide
Customization Guide
You’ve reached the end of the free preview
All Chapters
Full Tool Suite
Source Files
Lifetime Updates
📦 Free sample included — download another copy or visit the store for the full product.