TL;DR
- 95.9% of the top million sites have detectable a11y failures. Mobile apps are not better, they're just harder to audit.
- Four things changed: on-device assistive AI, ML-assisted testing, generated alt text and captions, and AI-assisted code generation.
- On-device AI raises the floor, not the ceiling. VoiceOver guessing "Button, likely a heart" is not a label.
- Rule-based tools catch 30 to 40% of WCAG failures. AI pushes that up, nowhere near 100%.
- The real fix is at generation time: if the model writes the JSX, it can write
accessibilityLabelin the same pass, for free.
The gap between apps shipping and apps shipping accessibly has been widening for a decade. What changed recently is that AI shows up on both sides of the shipping fence: in the runtime layer (the phone), in the tooling layer (audits), and at the code-generation layer, where the app is actually being written.
Why mobile a11y is harder than the web
Native apps don't share a common semantic model. On the web you have HTML, and HTML has a built-in accessibility contract. On mobile you have UIAccessibility on iOS, AccessibilityNodeInfo on Android, two screen readers with different gesture conventions, and a framework translation layer (React Native, Flutter, SwiftUI) sitting on top of both.
That means a label that works on one platform can be silently dropped on the other. Here's the version everyone writes first:
// Ships. Announces as "Button". Useless.
<Pressable onPress={toggleFavorite}>
<Icon name={isFavorite ? "heart-filled" : "heart"} />
</Pressable>
And the version that actually works with VoiceOver and TalkBack:
<Pressable
onPress={toggleFavorite}
accessibilityRole="button"
accessibilityLabel="Add to favorites"
accessibilityHint="Saves this item to your favorites list"
accessibilityState={{ selected: isFavorite }}
hitSlop={12}
>
<Icon name={isFavorite ? "heart-filled" : "heart"} />
</Pressable>
Four extra props. Nobody argues they're hard. They just never get written, because they're invisible in the simulator and they're the last-day task that gets cut.
Regulation is closing in anyway: the European Accessibility Act took effect for consumer digital products in June 2025, and ADA Title II requires state and local government apps to hit WCAG 2.1 AA by April 2026. Regulation without automation is a punishment. AI is what makes the automation possible.
Shift 1: the OS started covering for you
iOS runs an on-device model that generates image descriptions for photos and unlabeled UI elements. Ship a button with no label and VoiceOver will guess: "Button, likely a play triangle." Android's TalkBack does the same with Gemini Nano, including for images inside third-party apps that never set contentDescription. Both platforms now generate Live Captions for any audio playing on the device. Voice Control on iOS understands intent, so "tap the little heart" resolves even when your label is favoriteButton.
The floor is rising. The ceiling is not. A guessed description loses to a real one every time, and the guess is silently wrong often enough to matter.
Shift 2: audits got cheap
Three categories worth knowing:
-
Rule engines plus ML (axe DevTools Mobile, Google's Accessibility Scanner). These now catch labels that exist but are meaningless, like
contentDescription="image1.jpg". - Visual regression plus ML (Applause, BrowserStack, testRigor). Diffs screens against known-good corpora and flags contrast ratios, small tap targets, low-legibility fonts.
- LLM audits. Feed in screenshots plus an accessibility tree dump, get back findings in plain English: "The 'Sign in with Apple' button has no accessibility label; VoiceOver will announce it as 'Button'."
You can wire the cheap version of the third one into CI yourself:
// jest + @testing-library/react-native
// Fails the build when an interactive element ships unlabeled.
import { render } from "@testing-library/react-native";
test("all buttons are labeled", () => {
const { UNSAFE_root } = render(<ProductScreen />);
const buttons = UNSAFE_root.findAll(
(n) => n.props.accessibilityRole === "button"
);
expect(buttons.length).toBeGreaterThan(0);
buttons.forEach((b) => {
expect(b.props.accessibilityLabel).toBeTruthy();
});
});
WebAIM's own numbers say automated tooling catches 30 to 40% of WCAG failures. AI raises it, not to 100%. Keep a human in the loop, ideally one who uses the tech.
Shift 3: the missing content is now generated
Alt text from vision models is table stakes. Whisper-class models made captions good enough for accessibility use in most languages. LLMs are producing plain-language versions of dense content on the fly, which is a genuine breakthrough for cognitive accessibility. Live cross-language captioning is built into the call stack on both platforms.
The catch: generated descriptions are only usually right, and a screen reader confidently reading a subtly wrong description is worse than one that says nothing.
Shift 4: fix it at generation time
This is the one that matters. When an LLM writes the screen, the accessibility props are not extra work, they're the same tokens. That flips the default from "no labels, ship it" to "labels came with the generation."
This is the bet RapidNative is built on: prompt in, real React Native and Expo code out, with accessibilityLabel, accessibilityRole, accessibilityHint, and accessibilityState attached at generation rather than bolted on later. An image comes out as accessibilityLabel="Sunset over the ocean" instead of a nameless <Image /> someone will theoretically label next sprint.
None of this is exclusive to one tool. A well-prompted Copilot, Cursor, or Claude does the same thing in a hand-written codebase. Put it in the repo rules and it applies to every generation:
<!-- .cursorrules / CLAUDE.md / copilot-instructions.md -->
Every interactive element must have accessibilityRole and accessibilityLabel.
Every Image must have accessibilityLabel or accessible={false}.
Touch targets must be >= 44x44 (use hitSlop when the visual is smaller).
Never use placeholder text as the only label for a TextInput.
What AI still can't do
- It tells you labels exist, not that the flow is usable. Reading order that jumps around passes every automated check.
- Generated alt text is generic. "A person" is compliant. "The founder of the org you're about to donate to" is what a sighted user sees.
- Cognitive accessibility is barely automatable. The fix is design work, not a tag.
- Live captioning fails contextually: wrong medication name, wrong price, wrong date. Plausible-but-wrong is the worst failure mode for exactly the users you were helping.
- Motor accessibility is under-covered because it doesn't map cleanly onto structured tests.
Treat AI as the intern who catches the obvious stuff at 10x speed. It makes a specialist's time higher-leverage. It doesn't replace them.
The checklist I'd run on any AI-generated app
- Every interactive element has
accessibilityLabel, plusaccessibilityRoleandaccessibilityHintwhere useful. - Images are labeled or explicitly marked decorative with
accessible={false}. - Contrast passes WCAG 2.2 AA (4.5:1 body, 3:1 large). Re-check after any palette tweak.
- Font scaling works. Test at 200%.
- Touch targets are 44x44 minimum. Generators over-index on clean small icons, so this is the most-violated rule in generated code.
- Forms have labels, not just placeholders.
- Video has captions.
- You personally turned on VoiceOver and TalkBack and completed the primary flow.
Point 4 is worth a snippet, since it's the one people get wrong quietly:
import { useWindowDimensions, PixelRatio, Text } from "react-native";
// Bad: fixed height locks text out of scaling
<View style={{ height: 44 }}><Text>Continue</Text></View>
// Better: let the row grow with the user's font scale
const scale = PixelRatio.getFontScale();
<View style={{ minHeight: 44 * scale, justifyContent: "center" }}>
<Text maxFontSizeMultiplier={2}>Continue</Text>
</View>
Where this goes next
WCAG 3.0 moves toward outcome-based scoring instead of binary pass/fail, which is far better suited to LLM evaluation. EAA enforcement in Europe starts producing fines and case law in 2026, which changes the internal politics of a11y work fast. And expect compliance tooling that lives inside the AI development pipeline: reviewing PRs, gating deploys, producing an audit trail.
The direction of travel is that accessibility becomes a property of how the app was built, not a coat of paint applied afterward.
What's the a11y bug that has burned you hardest in a shipped app? Drop it in the comments. I'm especially interested in the ones no automated audit caught.
Top comments (0)