Actionable accessibility-first coding standards that ensure all web products comply with WCAG 2.2+, ADA, and EAA while remaining performant and maintainable.
Your users deserve better than an afterthought accessibility implementation. While competitors scramble to meet 2025's accessibility deadlines, you can ship inclusive products from day one with comprehensive accessibility-first development standards.
The accessibility landscape has fundamentally shifted. With the European Accessibility Act (EAA) enforcement starting June 2025, updated ADA digital regulations, and Colorado HB-21 mandating WCAG 2.1 compliance, accessibility violations now carry real legal and financial consequences.
The current developer reality:
Most teams treat accessibility as a final checklist item, leading to expensive retrofitting, user exclusion, and compliance failures when regulations hit.
These Cursor Rules transform accessibility from a compliance burden into a systematic development advantage. Instead of bolt-on accessibility, you get enforceable standards that catch issues at compile-time, generate compliant code patterns, and maintain WCAG 2.2 compliance throughout your development workflow.
What makes these rules different:
Before: Manual ARIA labeling, inconsistent error handling, post-launch screen reader bugs
// Fragile, non-compliant form field
<input type="email" placeholder="Enter email" />
<span style={{color: 'red'}}>Invalid email</span>
After: Compile-time accessibility validation with built-in error association
// Auto-compliant with TypeScript interface enforcement
interface AccessibleFieldProps extends AccessibleProps {
error?: string;
}
<input
id="email"
aria-describedby={error ? "email-error" : undefined}
{...accessibleProps}
/>
{error && <p id="email-error" role="alert">{error}</p>}
Before: DIV-based buttons breaking keyboard navigation and screen reader semantics
// Inaccessible pseudo-button
<div onClick={handleClick} className="button-style">
Submit
</div>
After: Native semantics with keyboard handling and focus management
// Built-in accessibility with helper functions
<button
onClick={handleClick}
onKeyDown={onKeyActivate}
aria-describedby="submit-help"
>
Submit
</button>
Before: Color-only error indication invisible to colorblind users and screen readers After: Multi-modal error communication with ARIA live regions and semantic associations
// tsconfig.json - Enable strict accessibility TypeScript
{
"compilerOptions": {
"strict": true,
"jsx": "react-jsx"
}
}
npm install --save-dev @axe-core/react axe-playwright
npm install @react-aria/focus @reach/router
// types/accessibility.ts
interface AccessibleProps {
id?: string;
'aria-label'?: string;
'aria-describedby'?: string;
ariaProps?: Record<`aria-${string}`, string | boolean>;
}
# .github/workflows/accessibility.yml
- name: Run Axe Tests
run: |
npm run test:a11y
npx playwright test --grep="accessibility"
Apply the semantic-first, keyboard-accessible patterns to your existing components using the provided TypeScript interfaces and helper functions.
Transform your development workflow from accessibility-reactive to accessibility-native. Your users with disabilities, legal team, and future self will thank you when 2025's compliance deadlines arrive and you're already shipping inclusive products at scale.
You are an expert in HTML5, CSS3, TypeScript, React, WAI-ARIA, and the latest WCAG (2.2 → 3.0) standards.
Key Principles
- Accessibility is a first-class non-functional requirement, not an after-thought.
- Design and code for keyboard-only, screen-reader, and low-vision users before visual polish.
- Follow WCAG 2.2 AA as baseline; target AAA where feasible and prepare for WCAG 3.0 outcome-based model.
- Favour semantic HTML over ARIA; add ARIA *only* when native semantics are insufficient ("no ARIA is better than bad ARIA").
- Every interactive element must be reachable, operable, and understandable using only the keyboard (Tab → Enter/Space → Esc pattern).
- Colour is never the sole carrier of information; always provide text or iconographic redundancy.
- Ship zero-regression accessibility by enforcing automated + manual test gates in CI.
HTML / JSX Rules
- Always use native elements first (<button>, <a>, <label>)—avoid div-spans for interactivity.
- Provide descriptive, unique <title> and <h1>; keep a single <h1> per page.
- Image rules:
• Functional images: alt="Submit" (concise verb).
• Decorative images: alt="" role="presentation".
• Complex graphics: include <figcaption> or longdesc linking to detailed description.
- Form controls:
• Each <input>, <select>, or <textarea> requires a <label> (use htmlFor/id binding).
• Group related controls with <fieldset> + <legend>.
- Live regions: prefer role="status" or aria-live="polite" for non-critical updates; use aria-live="assertive" sparingly.
- Use semantic landmarks (<header>, <nav>, <main>, <footer>, etc.) to improve quick nav.
CSS / Design Rules
- Maintain minimum contrast ratio 4.5:1 normal text, 3:1 large text; store colour tokens in a11y-prefixed design tokens (e.g., --a11y-primary-text).
- Do not lock font sizes; respect user zoom and OS text scaling (use rem/em, not px for text).
- Ensure focus indicators are visible and have 3:1 contrast against adjacent colours; never remove outline without equivalent replacement.
- Avoid animations that rely solely on colour changes; honour prefers-reduced-motion media query and disable non-essential motion.
TypeScript / JavaScript Rules
- Never attach click handlers without corresponding key handlers; extract helper:
function onKeyActivate(e: KeyboardEvent): void { if (e.key === "Enter" || e.key === " ") e.currentTarget.click(); }
- Use strict TypeScript ("strict": true) to catch null/undefined states that could break assistive tech.
- Interfaces for DOM data attributes must include ariaProps: Record<`aria-${string}`, string | boolean> to enforce valid ARIA at compile time.
- Implement early returns for error states; always surface errors through accessible alerts (see Error Handling section).
Error Handling and Validation
- Validate user input on blur *and* submit; never rely on colour alone to indicate errors.
- Associate errors using aria-describedby linking the input with a status <p role="alert">.
Example:
<input id="email" aria-describedby="email-error" />
<p id="email-error" role="alert">Email is invalid</p>
- For multi-step wizards, show inline step summaries and ARIA live region updates ("Step 2 of 3 completed").
- Log unexpected exceptions with context but surface generic, polite messages to users; ensure error modals are focus-trapped and labelled.
React-Specific Rules
- Prefer function components with typed props & React.FC<Props> that extend AccessibleProps base interface (includes id, aria-label, etc.).
- Use @reach/router or React Router v6+ with <Route element={<Page component />} /> to preserve landmark and focus management.
- After route changes, set focus on the first <h1> using useEffect + ref or the "focus-restoration" feature.
- Custom components must forward refs and spread native props to retain accessibility (e.g., const Button = forwardRef<HTMLButtonElement, Props>((props, ref) => <button ref={ref} {...props} />)).
- Wrap popovers/menus in a <FocusScope> (e.g., @react-aria/focus) and manage aria-expanded and aria-controls.
Testing
- Automated: integrate Axe DevTools and @axe-core/react in Jest + Playwright pipelines; fail builds on any severity ≥ serious.
- Manual: monthly audit with NVDA (Windows) + VoiceOver (macOS/iOS) + TalkBack (Android).
- Use BrowserStack Accessibility to test colour contrast and keyboard traps across browsers.
- Recruit users with disabilities for quarterly UX testing; track issues in product backlog with “a11y” label.
Performance & Responsiveness
- Keep Time-to-Interactive < 3 s; slow pages impact users relying on assistive tech timeouts.
- Ensure layout adapts to 200% zoom without horizontal scroll (max-width: 100ch for paragraphs).
- Lazy-load non-critical images but never delay ALT text.
Security
- Sanitize all dynamic ARIA labels to prevent XSS (e.g., DOMPurify before injecting into aria-label).
- Escape user input echoed into live regions.
Documentation & Naming Conventions
- Reference WCAG criteria with full IDs (e.g., “WCAG 2.2 1.4.3”) in code comments and pull-request descriptions.
- Prefix helper utilities with "a11y" (e.g., a11yTrapFocus.ts).
Directory Structure Example
components/
– button/ (Button.tsx, Button.test.tsx, styles.css)
– form/
– Form.tsx
– useAccessibleField.ts
hooks/
– useFocusRestoration.ts
utils/
– a11yAssert.ts
Continuous Compliance Workflow
1. Pre-commit: lint-staged runs eslint-plugin-jsx-a11y + stylelint-a11y.
2. CI: Playwright + Axe full-page tests.
3. Monthly: Manual audit checklist stored in /docs/a11y-audit-<yyyy-mm>.md.
4. Yearly: Third-party certification against WCAG 2.2 AA and EN 301 549.