# Accessibility Code Patterns Practical, copy-paste-ready patterns for common accessibility requirements. Each pattern is self-contained and linked from the main [SKILL.md](../SKILL.md). --- ## Modal focus trap Trap keyboard focus inside a modal dialog so Tab/Shift+Tab cycle through its focusable elements and Escape closes it. ```javascript function openModal(modal) { const focusableElements = modal.querySelectorAll( 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])' ); const firstElement = focusableElements[0]; const lastElement = focusableElements[focusableElements.length - 1]; modal.addEventListener('keydown', (e) => { if (e.key === 'Tab') { if (e.shiftKey && document.activeElement === firstElement) { e.preventDefault(); lastElement.focus(); } else if (!e.shiftKey && document.activeElement === lastElement) { e.preventDefault(); firstElement.focus(); } } if (e.key === 'Escape') { closeModal(); } }); firstElement.focus(); } ``` The native `` element handles focus trapping automatically—prefer it when browser support allows. --- ## Skip link Allows keyboard users to bypass repetitive navigation and jump straight to main content. ```html
``` ```css .skip-link { position: absolute; top: -40px; left: 0; background: #000; color: #fff; padding: 8px 16px; z-index: 100; } .skip-link:focus { top: 0; } ``` --- ## Error handling Announce errors to screen readers and focus the first invalid field on submit. ```html
``` ```javascript form.addEventListener('submit', (e) => { const firstError = form.querySelector('[aria-invalid="true"]'); if (firstError) { e.preventDefault(); firstError.focus(); const errorSummary = document.getElementById('error-summary'); errorSummary.textContent = `${errors.length} errors found. Please fix them and try again.`; errorSummary.focus(); } }); ``` --- ## Form labels Every input needs an associated label—either explicit (`for`/`id`) or implicit (wrapping `