AI A11y Toolkit
The AI A11y Toolkit is a free set of three files you install into your AI builder so the code, components, and content it generates meet WCAG 2.2 Level AA by default.
Release 2026.07. Last reviewed 31 July 2026.
AI can build you a working interface in ninety seconds. It will also give you buttons that are not buttons, forms without labels, carousels that cannot be paused, focus outlines stripped out for looking untidy, and alt text that reads "IMG_4471".
Not because the model is careless. Because nobody told it the rules, and it has been trained on twenty years of the internet doing this wrong. The most common pattern in the training data is the inaccessible one, so the most common pattern is what you get.
The result looks finished and locks people out, and it ships faster than anyone can review it. That last part is the bit that should worry you.
Why your AI builds inaccessible interfaces
This is the thing most accessibility guidance skips.
If you paste a list of rules into a chat message, your tool follows them for a few turns and then quietly stops. Chat context decays. Twenty prompts later the model has moved on to whatever you said most recently, and you are back to generated defaults without any warning that it happened.
The rules have to live somewhere the tool reads on every single request. Every AI builder has such a place. They are all named something different, they are all in a different menu, and several of them fail silently if you get the filename slightly wrong. A plain .md file in Cursor's rules folder, for instance, is ignored outright. It has to be .mdc with frontmatter.
Working out where that place is, for the tool you actually use, is what START-HERE.md is for.
Why pasting the rules into chat does not work
What is inside
The setup guide. Exact menu paths for 15 platforms, from Lovable's Knowledge panel to a .cursor/rules file to Figma Make's guidelines folder. Includes an activation prompt that makes your AI quote a rule back to you, so you can confirm it actually loaded instead of hoping.
START-HERE.md
The condensed version, sized to fit platform text fields that cap out around ten thousand characters. Every hard rule, none of the explanation. This is the one you paste into Lovable or Base44.
ACCESSIBILITY-CORE.md
The full reference, 18 sections, all 55 Level A and AA success criteria written as build instructions rather than as standards language. Split by job function, so designers, web developers, framework engineers, and people prompting for AI-generated content each have their own section. This is the one you commit to a repo.
ACCESSIBILITY.md
What it will not do
Worth saying plainly, because the alternative is you finding out later.
Automated accessibility checking detects roughly a third of defects. No file, and no AI, can tell you whether your alt text is accurate, whether your focus order makes sense to a person, or whether your error message actually helps someone recover. That needs a human with a keyboard and a screen reader, and ideally a disabled tester who is paid for their time.
This toolkit will not make you compliant. It will stop your AI from generating the obvious failures by default, and it will tell you honestly what is left to check. That is a large improvement on the default, and it is not the same as done.
Designers and non-developers building real things with AI. Engineers who want the rules in the repo instead of in a Slack thread. Product teams shipping AI-assisted work faster than review can keep up. Workshop facilitators, since there is a facilitation sequence built into the last section.
Yes. Three markdown files, licensed CC BY 4.0, free to download, share, and adapt with attribution.
Who it is for
Accessibility rules (core)
Part of the AI A11y Toolkit by Dana Randall. Release 2026.07. Current version and the full reference: the AI A11y Toolkit page
Condensed from ACCESSIBILITY.md. Target: WCAG 2.2 Level AA. Use this short version where a platform caps how much text you can save. Use the full file where you can commit a file to a repo.
You are building for people using screen readers, keyboards only, switch access, voice control, magnification, and for people with motion sensitivity, low vision, color vision deficiency, and cognitive disabilities. These rules are constraints, not preferences.
Before you build anything
If you do not know which design system, component library, or token set this project uses, STOP and ask me. Do not choose one silently. Do not hand-roll components. Tailwind and other CSS frameworks are styling only, they contain no accessible components, so they are not an answer to this question.
Always
- Use semantic HTML first.
buttonfor actions,awithhreffor navigation, reallabel,fieldset,table,ul. Reach for ARIA only when no element exists. - Every interactive element is reachable and operable by keyboard alone, in a logical order, with a visible focus indicator at 3:1 contrast or better against adjacent colors.
- Every form control has a programmatically associated visible label. Placeholder text is not a label.
- Every image that carries meaning has alt text that says what it means in this context. Decorative images get
alt="". Never a filename, never a SKU, never a color code like "RD-100". Say "bright red pebbled leather" instead. - Text contrast at least 4.5:1. Large text, meaning 24px regular or 18.66px bold and above, at least 3:1. Icons, control borders, focus rings, and meaningful graphics at least 3:1. State the ratio you calculated.
- Interactive targets at least 44x44 CSS pixels, with at least 8px between adjacent targets.
- Text reflows with no clipping or overlap at 200% text zoom, at 400% page zoom, and at 320px width. Use relative units. Never fix the height of a container holding text.
- One
h1per page, headings in order with no skipped levels, real landmarks, a skip link, a descriptive page title, andlangonhtml. - Respect
prefers-reduced-motion,prefers-reduced-transparency, andprefers-contrast. - Announce dynamic changes through a live region that already exists in the DOM before its content updates.
- Error messages appear in text next to the field, say what is wrong and how to fix it, and never clear the user's input.
- Use the project's design tokens. No arbitrary hex values or magic numbers.
Normalise any markup you inject. Anything passed through dangerouslySetInnerHTML, v-html, or innerHTML is invisible to linting, so decide at the injection point whether it is decorative or meaningful. Decorative injected SVG gets aria-hidden="true" and focusable="false". Meaningful content gets a name on a wrapper you control.
Audit color tokens as data, not only as screens. Compute every documented foreground and background pair in every theme. Judge text pairs at 4.5:1, and judge control boundaries, focus rings, icons, and state indicators at 3:1 under 1.4.11. Border and input tokens are the ones reviewers miss, because a faint boundary is far less obvious than faint body text.
Never
- Never remove focus styles, and never use
outline: noneoroutline: 0without an equivalent replacement. - Never use positive
tabindexvalues. - Never use a
divorspanwith a click handler as a control. - Never nest interactive elements, such as a button inside a link.
- Never put
aria-hidden="true"on a focusable element or any of its ancestors. - Never use
aria-labelon a non-interactive element with no role and expect it to be announced. - Never use color, position, shape, or sound as the only way information is conveyed. Errors, required fields, status, availability, chart series, and links inside body text all need a second cue. Underline links in running text.
- Never hand-roll a dialog, combobox, select, menu, tabs, tooltip, date picker, slider, or carousel. Use a tested primitive from the project's design system.
- Never mix two component libraries in the same surface.
- Never auto-play audio longer than 3 seconds without a control.
- Never build a carousel, slideshow, or auto-advancing anything without a persistent, labeled, keyboard-reachable pause control. Minimum interval 5 seconds.
- Never autoplay or loop background video without a pause control.
- Never use parallax, scroll-jacking, or scroll-triggered reveal chains.
- Never use infinite or looping animation, marquees, tickers, or looping GIFs.
- Never use bounce, spring, elastic, or overshoot easing, spinning, 3D rotation, or blur transitions.
- Never animate full-page transitions, and never animate text in word by word.
- Never let anything flash more than 3 times per second.
- Never exceed 400ms on a transition, and never block interaction until an animation finishes.
- Never set fixed heights, line clamps, or
overflow: hiddenon containers holding text. - Never position a sticky, fixed, or absolute element where it can cover text when text size grows.
- Never require a puzzle, transcription, or memory test to authenticate. Allow paste and password managers in every credential field.
- Never ask for information the user already gave you in the same flow.
- Never impose a time limit without a way to extend, adjust, or turn it off.
- Never stack modals, toasts, or interruptions, and never auto-dismiss on a timer.
- Never build a "color blind mode", accessibility toggle, or overlay widget. Fix the default.
- Never gate an accommodation behind a setting the user has to find.
- Never generate lorem ipsum alt text, filename alt text, or "image of" prefixes.
- Never suppress, ignore, or baseline an accessibility finding to make a check pass.
- Never claim your output is "accessible" or "WCAG compliant". Say what you did and what still needs human and screen reader testing.
Motion policy
Motion is off by default under prefers-reduced-motion: reduce. Otherwise: 100 to 150ms for hover and focus, 150 to 250ms for state changes, 200 to 300ms for disclosure, 250 to 400ms for modals. Animate opacity and transform only. Motion is never the only signal that something changed.
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
Writing
Short sentences, common words, active voice. Label buttons with the action performed, such as "Save draft", never "OK" or "Submit". Link text describes the destination, never "click here" or "learn more". Expand abbreviations on first use. Avoid idiom and sarcasm in interface copy. Sentence case, not all caps. One primary action per view.
Check your work
After you generate or change UI, run an automated accessibility check and fix what it finds at the source. Use an open source engine such as the IBM Equal Access Accessibility Checker (accessibility-checker on npm) or Pa11y. If the project already uses the Level Access platform, @userway/a11y-playwright is also fine. Do not substitute another engine. One engine passing is not proof a page is accessible, so run a second when you can. Then write the things a scanner cannot judge into docs/accessibility/MANUAL-TESTING.md: keyboard operation, focus order, screen reader announcements, whether alt text is accurate, and whether the copy is clear. For each item, say what to test, how to test it, and what the correct result is. Never mark those items as passed, because you cannot run them.
Prove the scan actually ran before you report the number. A scanner reports on whatever was in the DOM when it looked, so a login wall, a consent banner, a loading skeleton, or an empty state will produce a clean result and exit successfully. Wait for a real element that only exists on the page you meant to scan, scroll to force lazy content to render, and record how many characters rendered. If the page is nearly empty, fail the run instead of reporting zero. Treat a zero result as a question: confirm the page rendered, and confirm the ruleset actually contains a rule for the thing you care about. An engine with no rule for a defect reports zero forever, and that looks exactly like a pass.
Automated tools find roughly a third of accessibility defects. Report what you scanned, what you fixed, and what a person still needs to verify.
When a request conflicts with these rules
Say so, explain the barrier in one sentence, and offer the accessible alternative. Do not quietly produce the inaccessible version.
Full reference, setup guide for 15 AI tools, and the current release: the AI A11y Toolkit page Something here not work in your tool? Tell me what broke
AI A11y Toolkit by Dana Randall, licensed CC BY 4.0. Keep this line if you adapt or redistribute these rules. Read the CC BY 4.0 licence
Does it actually work
I tested it rather than assuming.
Two AI agents, the same model, the same build brief, run at the same time. One had the toolkit installed. One had nothing. The brief asked for an icon browser and never mentioned accessibility once, but it quietly laid traps in the kind of language a real client uses: inject the icons as raw SVG strings, keep the search chrome minimal, show status in green, amber and red, make the cards compact, add a subtle lift on hover, open a centered overlay on a dimmed backdrop. I wrote the scoring rubric before either build started, so I could not move the goalposts afterward.
Then I scanned both with the same engine and hand-checked the things no engine can see.
AUTO means a browser based engine can find it. MANUAL means no engine can, and it has to be read out of the code or the DOM. Nine of the sixteen checks are manual only.
| Check number | Check | WCAG | Detection | Without the toolkit | With the toolkit |
|---|---|---|---|---|---|
| 1 | Injected SVG neutralised or named | 1.1.1 | AUTO | Fail | Pass |
| 2 | Injected SVG not focusable | 2.1.1 | MANUAL | Fail | Pass |
| 3 | Icon card has an accessible name | 4.1.2 | AUTO | Pass | Pass |
| 4 | Copy buttons distinguishable from each other | 2.4.6 | AUTO | Fail | Pass |
| 5 | Search input programmatically labelled | 3.3.2 | AUTO | Pass | Pass |
| 6 | Copy result announced | 4.1.3 | MANUAL | Fail | Pass |
| 7 | Dialog has a role and a name | 4.1.2 | AUTO | Pass | Pass |
| 8 | Focus moves into the dialog on open | 2.4.3 | MANUAL | Pass | Pass |
| 9 | Focus trapped while open, restored on close | 2.4.3 | MANUAL | Fail | Pass |
| 10 | Escape closes the dialog | 2.1.2 | MANUAL | Pass | Pass |
| 11 | Toggle state exposed | 4.1.2 | AUTO | Fail | Pass |
| 12 | Reduced motion honoured | 2.3.3 | MANUAL | Fail | Pass |
| 13 | Visible focus indicator | 2.4.7 | MANUAL | Fail | Pass |
| 14 | Status not conveyed by color alone | 1.4.1 | MANUAL | Pass | Pass |
| 15 | Non-text contrast reaches 3:1 | 1.4.11 | MANUAL | Fail | Fail |
| 16 | Native semantics, no ARIA on bare elements | 1.3.1, 4.1.2 | AUTO | Fail | Pass |
| Total | 6 of 16 | 15 of 16 |
The version without the file walked into every trap. It built cards as div elements pretending to be buttons, with a real button nested inside. It gave twelve copy controls the identical name "Copy". It put the copy buttons at 39 by 17 pixels, held them at zero opacity until hover, and left them in the tab order the entire time, so a keyboard user tabs into twelve invisible undersized controls. It stripped the focus outline and replaced it with a border color change. It handled reduced motion nowhere.
The version with the file avoided all of that. Same model, same brief, same traps.
The part that matters more than the score
The toolkit build still failed one check. Its border and input tokens came in between 1.4:1 and 2.4:1 against their backgrounds, where 3:1 is required, and those borders were the only thing marking the edge of the search field. No engine caught it in either version, because engines measure text pixels rather than asking whether a boundary is the only thing identifying a control. I only found it by computing every color pair in both themes by hand.
That build also overstated itself. It reported 44 by 44 pixel targets when the real number was 32 by 32, and claimed contrast-checked palettes while its borders were failing. An AI following accessibility rules will still tell you it did better than it did.
Five of the nine checks the unguided build failed are invisible to every automated tool on the market. Both builds shipped with no main landmark and no skip link. This is one study, one model, one brief, and it measures whether the rules get followed rather than whether the result is usable by a real person.
So: the file prevents the obvious failures by default, and it does that reliably. It does not replace testing, and it does not replace disabled people telling you what is broken.
The full brief, the pre-registered rubric, both codebases, the raw scan output and the contrast math is all published, so you can rerun it and disagree with me. Read the research
Feedback
Common questions / FAQ
How do I make AI generated code accessible?
Install a standing rules file into your AI tool's instructions or knowledge field rather than pasting rules into chat. Chat context decays. The AI A11y Toolkit provides that file, mapped to WCAG 2.2 Level AA, plus setup instructions for 15 platforms.
Does Lovable generate accessible code?
Not by default. Lovable, like every AI builder, generates whatever pattern is most common in its training data, which frequently means non-semantic elements, missing labels, and stripped focus indicators. Adding accessibility rules to Lovable's Project Knowledge field applies them to every prompt.
Where do I put accessibility rules in Cursor?
In a .cursor/rules/accessibility.mdc file with alwaysApply set to true in the frontmatter. A plain .md file in that folder is ignored.
Can AI test accessibility?
Partially. Automated engines detect roughly one third of accessibility defects. The remainder, including whether alt text is accurate and whether focus order makes sense, requires a person using a keyboard and a screen reader. The toolkit has the AI generate a manual testing file for exactly that reason.
Is the AI A11y Toolkit free?
Yes. Three markdown files, licensed CC BY 4.0, free to download, share, and adapt with attribution.