Skip to content
BlackFig

Making an AI-built app accessible (WCAG 2.2)

AntPublished 5 min read

Quick answer

Aim for WCAG 2.2 level AA. AI-built apps usually start from accessible components, then lose it in the custom parts: clickable divs, icon buttons with no name, missing focus outlines, placeholder-only labels, low-contrast text, tiny targets and errors shown only in colour. Check each area below against its success criterion and test with a keyboard.

On this page
  1. Why it matters
  2. The checklist
  3. Common misses in AI-generated code
  4. Next step

Why it matters

Accessibility is about whether people can use your product at all: people using a keyboard, a screen reader, voice control, a magnifier, or simply a phone in bright sunlight with a shaky hand. If they cannot sign up, they are not your users.

The standard to work to is the W3C's Web Content Accessibility Guidelines, WCAG 2.2. The current version of the W3C Recommendation is dated 12 December 2024. It extends WCAG 2.1, and content that conforms to 2.2 also conforms to 2.0 and 2.1. It added nine success criteria and removed one, 4.1.1 Parsing, which is now marked obsolete. Each criterion has a level: A, AA or AAA. Aim for AA, which means meeting every A and AA criterion.

AI-built apps have a specific pattern. The component layer is often good: shadcn/ui says it is built with Radix UI primitives, and Radix says its primitives follow the WAI-ARIA authoring practices, including keyboard support and focus management. The problems appear in the custom code the AI writes around those components, and in the colour, copy and layout choices made with nobody checking.

What is new in 2.2, and why it hits AI-built apps

If you last looked at accessibility under WCAG 2.1, these are the nine additions. Several land squarely on patterns AI builders like to generate.

CriterionLevelWhere AI-built apps trip on it
2.4.11 Focus Not Obscured (Minimum)AASticky headers, floating chat buttons and cookie banners covering the focused field
2.4.12 Focus Not Obscured (Enhanced)AAASame as above, but no part of the focused element may be hidden
2.4.13 Focus AppearanceAAAThin or low-contrast focus rings
2.5.7 Dragging MovementsAAKanban boards and sortable lists that only work by dragging
2.5.8 Target Size (Minimum)AASmall icon buttons packed into table rows and toolbars
3.2.6 Consistent HelpAHelp links that move between pages, or appear on some and not others
3.3.7 Redundant EntryAMulti-step forms that ask for the same address or email twice
3.3.8 Accessible Authentication (Minimum)AAPassword fields that block paste, or custom sign-in that breaks password managers
3.3.9 Accessible Authentication (Enhanced)AAASign-in that relies on recognising images or objects

The fixes are rarely large. Most are a scroll-padding value, a bigger hit area, a Move to menu or a correct autocomplete attribute. The hard part is knowing to look.

This checklist groups the criteria that AI-built apps most often fail, each with its number and level, so you can look up the exact wording on the W3C site.

The checklist

Structure and meaning

The page makes sense without seeing it

  • 1.3.1 Info and Relationships (A): headings use h1 to h3 in order, lists are real lists, tables use th, and form fields are tied to their labels.
  • 2.4.2 Page Titled (A): every route sets a title that describes the page, not just the product name.
  • 3.1.1 Language of Page (A): the html element has a lang attribute, such as en-GB.
  • 2.4.1 Bypass Blocks (A): a skip link or landmarks (header, nav, main) let people jump past repeated navigation.
  • 2.4.6 Headings and Labels (AA): headings and labels describe their topic or purpose. No emoji-only or decorative headings.
  • 1.1.1 Non-text Content (A): meaningful images have alt text, decorative ones have empty alt, and icon-only controls have a name.

Keyboard and focus

Everything works without a mouse

  • 2.1.1 Keyboard (A): every action works with a keyboard. Clickable divs and spans are replaced with buttons and links.
  • 2.1.2 No Keyboard Trap (A): focus can always move out of a component, including custom modals, editors and embedded widgets.
  • 2.4.3 Focus Order (A): Tab moves through the page in an order that matches the layout and meaning.
  • 2.4.7 Focus Visible (AA): a focus indicator is visible on every interactive element. No outline-none without a replacement.
  • 2.4.11 Focus Not Obscured (Minimum) (AA, new in 2.2): a focused element is never entirely hidden behind a sticky header, footer, chat widget or cookie banner.

Colour and contrast

It can be read by everyone

  • 1.4.3 Contrast (Minimum) (AA): body text has a contrast ratio of at least 4.5:1. Large text, at least 18 point or 14 point bold, needs 3:1.
  • 1.4.11 Non-text Contrast (AA): input borders, focus indicators, icons and chart elements needed to understand the interface reach at least 3:1 against what is next to them.
  • 1.4.1 Use of Color (A): colour is never the only way to show an error, a status, a selected item or a link. Add text, an icon or an underline.

Forms and sign-in

People can complete every form

  • 3.3.2 Labels or Instructions (A): every input has a visible label. Placeholder text alone does not count.
  • 3.3.1 Error Identification (A): when an error is detected, the field is identified and the error is described in text.
  • 3.3.3 Error Suggestion (AA): when you know how to fix an error, say so, such as the expected date format.
  • 1.3.5 Identify Input Purpose (AA): personal data fields use the right autocomplete values, such as email, name and new-password.
  • 3.3.7 Redundant Entry (A, new in 2.2): information already entered in the same process is filled in or offered, not asked for again.
  • 3.3.8 Accessible Authentication (Minimum) (AA, new in 2.2): sign-in does not depend on remembering or transcribing something. Allow paste and password managers, or offer email link, OAuth or WebAuthn sign-in.
  • 4.1.2 Name, Role, Value (A): custom controls like toggles, tabs and comboboxes expose their name, role and state to assistive technology.

Touch, pointer and layout

It works at any size and with any pointer

  • 2.5.8 Target Size (Minimum) (AA, new in 2.2): pointer targets are at least 24 by 24 CSS pixels, or spaced so a 24px circle around each does not overlap another.
  • 2.5.7 Dragging Movements (AA, new in 2.2): anything done by dragging, such as reordering a list or moving a kanban card, can also be done with single clicks or taps.
  • 1.4.10 Reflow (AA): content works at 320 CSS pixels wide without scrolling in two directions, apart from things like data tables and maps that need two dimensions.
  • 1.4.4 Resize Text (AA): text can be zoomed to 200 percent without losing content or functions.
  • 1.4.12 Text Spacing (AA): nothing breaks when users increase line height, paragraph, letter and word spacing.

Dynamic content

Changes are announced and controllable

  • 4.1.3 Status Messages (AA): messages like Saved, 3 results or Upload failed are announced by screen readers without moving focus, using role status or alert.
  • 1.4.13 Content on Hover or Focus (AA): tooltips and popovers can be dismissed without moving the pointer, can be hovered themselves, and stay visible until the pointer or focus moves away or the user dismisses them.
  • 2.2.2 Pause, Stop, Hide (A): anything that moves, auto-scrolls or auto-updates for more than five seconds alongside other content can be paused or hidden.
  • 3.2.6 Consistent Help (A, new in 2.2): if you offer help, such as a contact link or chat, it appears in the same relative place on every page.
  • 2.3.3 Animation from Interactions (AAA, optional): motion triggered by interaction can be turned off. Respecting prefers-reduced-motion covers most of this cheaply.

Common misses in AI-generated code

These are the patterns to search the codebase for first. Each one is quick to fix once you know it is there.

Clickable divs. div and span elements with an onClick look like buttons but cannot be reached with Tab or triggered with Enter, which fails 2.1.1. Replace them with button for actions and Link for navigation.

Icon buttons with no name. A trash can or a three-dot menu with no text has no accessible name, which fails 1.1.1 and 4.1.2. The shadcn/ui docs' own button example shows the fix:

<Button variant="outline" size="icon" aria-label="Delete project">
  <Trash2 />
</Button>

Note that the default icon size is size-9, 36px, which passes 2.5.8. The newer icon-xs size is size-6, exactly 24px, so check spacing if you use it in a dense row.

Removed focus outlines. Generated styles sometimes add outline-none for a cleaner look. shadcn/ui components replace the outline with a ring on focus-visible, which is fine. Custom elements often have nothing, which fails 2.4.7.

Placeholder labels. A single input with "Email address" as the placeholder and no label is a very common generated pattern. The label disappears as soon as someone types. Add a visible label tied to the input with htmlFor.

Muted text on tinted backgrounds. Grey helper text can pass 4.5:1 on white and fail on a light tinted card or a coloured banner. Check the actual pairs, not the token in isolation.

Errors in colour only. A red border with no message fails 1.4.1 and 3.3.1. Add the message in text next to the field.

Toasts for everything. A toast that disappears after a few seconds is the only feedback for many generated actions. Give it role="status" so it is announced, and for errors that need action, show them inline as well.

Drag-only interfaces. Kanban boards and sortable lists are a favourite of AI builders, and they often work only by dragging. 2.5.7 asks for a single-pointer alternative, such as a Move to menu on each card.

Charts. The shadcn/ui chart component has an accessibilityLayer prop that adds keyboard access and screen reader support. Turn it on, and add a short text summary of what the chart shows.

Motion. Tailwind's motion-reduce: variant makes it easy to respect the user's setting:

<div className="transition-transform duration-300 motion-reduce:transition-none">
  {/* animated panel */}
</div>

Next step

Do these in order. Each takes less than an hour on a small app.

  1. Run an automated check on your three busiest screens with axe DevTools or Lighthouse. Fix everything it finds. These are the cheap wins: missing labels, missing names, low contrast.
  2. Unplug the mouse. Complete sign-up, the main task and sign-out with only Tab, Shift+Tab, Enter, Space, Escape and the arrow keys. Note every point where focus vanishes, gets stuck or jumps.
  3. Zoom to 200 percent and narrow the window to 320px. Note anything cut off, overlapping or scrolling sideways.
  4. Turn on a screen reader for one flow: VoiceOver on a Mac, NVDA on Windows. Listen for unnamed buttons and silent status changes.
  5. Fix the colour tokens once, in your theme, rather than screen by screen. How to make a shadcn app not look like shadcn shows where they live.

Accessibility work overlaps heavily with general UX fixes. Many items above also appear in UX mistakes AI tools make in every app, and the missing states in empty states, errors and loading states AI forgets are often where 4.1.3 fails.

If you would rather have it designed in from the start, that is how I work: accessible structure, contrast and states are part of the design and the build, not a pass at the end. See FindPopups for a product I designed and built, or the design guide for AI-built apps for where accessibility fits with the rest.

Questions founders ask

Which WCAG level should an MVP aim for?

Level AA. It includes all level A criteria plus the AA ones, and it is the level most accessibility policies and procurement checklists refer to. Level AAA is useful guidance but is not usually required for a whole product.

Are shadcn/ui components accessible?

The components are built on accessible primitives and handle much of the keyboard and screen reader behaviour for you. Accessibility is usually lost in the custom code around them, and in colour and copy choices.

Can an automated checker make my app WCAG compliant?

No. Tools like axe or Lighthouse catch a useful set of problems, such as missing labels and low contrast, but many criteria need a person: whether focus order makes sense, whether error messages help, whether link text is clear.

Ant

Product designer who builds MVPs, based in Nottingham. 10+ years designing digital products, and the only person at BlackFig. More about me