How do you make a web app UI accessible?
You make a web app UI accessible by designing every interaction for keyboard, screen reader, zoom and reduced motion from the first wireframe, then testing it with those tools before release. The target most teams use is WCAG 2.2 at level AA. Marketing-site accessibility is mostly about content and contrast; product accessibility is mostly about interaction and state.
This checklist is product-specific: tables, modals, menus, charts, live updates and focus management. For contrast, type and focus-ring basics, start with accessible design basics. For the wider pattern library, see our guide to web app UI design. The standard itself is on the W3C WCAG overview.
What is the accessible web app design checklist?
The checklist below is the order we review a product in. Each item is something a designer can specify and an engineer can verify.
- Keyboard reachability: every interactive element can be reached with Tab and used with Enter, Space or arrow keys.
- Visible focus: a clear focus indicator on every element, designed as a real state in Figma, never removed.
- Logical focus order: focus follows the visual reading order, including in sidebars and toolbars.
- Skip links and landmarks: a skip-to-content link and named regions for navigation, main content and panels.
- Managed focus in overlays: modals, drawers and popovers move focus in, trap it while open and return it on close.
- Semantic tables: data grids use table markup with header cells, captions and sortable column states announced.
- Labelled forms: every field has a visible, linked label; errors are tied to fields and announced.
- Announced updates: toasts, saves, filters and async results are announced through live regions.
- Chart alternatives: each chart has a text summary and an accessible data table.
- Zoom and reflow: the app works at high browser zoom without losing content or functions.
- Motion and color: reduced-motion respected, and meaning never carried by color alone, in light and dark themes.
- Names for icon buttons: every icon-only control has an accessible name that matches its tooltip.
How should focus be managed in a web app?
Focus should always be visible, move predictably, and land somewhere sensible after anything changes the page. Single-page apps break this by default: content changes without a page load, so the browser doesn't know where to put focus.
- After route changes, move focus to the new page's main heading so screen-reader users hear where they are.
- After deleting an item, move focus to the next item or the list heading, not back to the top of the document.
- After a failed submit, move focus to the error summary or the first invalid field.
- After closing an overlay, return focus to the control that opened it.
- Never trap focus by accident in embedded widgets like rich text editors; provide a documented way out.
How do you make modals, menus and comboboxes accessible?
Make overlays accessible by following the documented keyboard patterns in the WAI-ARIA Authoring Practices Guide rather than inventing new ones. Users who rely on keyboards and screen readers have learned those patterns, and deviations feel broken.
Component | Keyboard behavior | What designers specify |
|---|---|---|
Modal dialog | Focus moves in, Tab cycles inside, Escape closes, focus returns | Initial focus target, title, close button, what Escape does |
Dropdown menu | Arrow keys move between items, Escape closes, Enter selects | Item order, disabled items, keyboard hints |
Combobox and autocomplete | Typing filters, arrows move through options, Enter picks | Empty and no-match states, how selections appear |
Tabs | Arrow keys switch tabs, Tab moves into the panel | Selected state, overflow behavior |
Command palette | Opens on shortcut, typing filters, arrows navigate, Escape closes | Result groups, shortcut labels, empty query suggestions |
Native elements save work: a real dialog element, a real button and a real select come with keyboard and screen-reader behavior built in. Headless libraries such as Radix UI implement these patterns for custom-styled components. Our guide to command palette design covers the most complex overlay most SaaS apps ship.
How do you make data tables and dashboards accessible?
Data tables are accessible when they use real table markup, so a screen reader can announce the column and row header for each cell. Div-based grids that only look like tables lose that context, and users hear a stream of unlabelled numbers.
- Use header cells for column headers, and for the first column when it names the row.
- Announce sort state on sortable columns, and make the sort control a button inside the header.
- Make row actions reachable by keyboard, not only on hover. A visible "More" button per row works.
- Keep selection clear: checkboxes with labels like "Select invoice 1042", plus a bulk-action bar that's announced when it appears.
- Choose grid behavior deliberately: a spreadsheet-like grid with arrow-key navigation is a different, more complex pattern than a table with links. Use it only when users edit cells.
Large tables also need to stay fast, because laggy keyboard navigation is its own accessibility failure. Our web app performance checklist covers virtualization and its accessibility trade-offs.
How do you make charts accessible?
Make charts accessible by giving each one a text summary of the insight and an accessible table of the underlying data. A chart is a picture of numbers; screen-reader users need the numbers and the point.
Write the takeaway as the title
"Signups rose every month in Q3" says more than "Signups by month", and it helps every reader.
Add a short text summary
One or two sentences with the key values, placed next to the chart.
Offer the data as a table
A "View as table" toggle or an expandable table gives exact values to everyone.
Don't rely on color
Use direct labels, patterns or shapes so series are distinguishable without color, in both themes.
Make interactive points reachable
If tooltips carry information, they must be reachable by keyboard, not just hover.
Live regions: announcing updates without stealing focus
Many product updates happen away from the user's focus: a save confirmation, a filter result count, a background import finishing. Screen-reader users miss these unless they're announced.
A live region is an element that assistive technology watches for changes. A polite region waits until the user pauses, which suits status messages like "Saved" or "18 results". An assertive region interrupts, so reserve it for urgent errors.
Design rules: write the announcement text as part of the spec (it's often different from the visual text), keep it short, and don't announce every keystroke in a live search. Put one shared status region in the app shell rather than scattering them across components. Toasts should use a live region and stay on screen long enough to read, or be dismissible and retrievable.
How should designers hand off accessibility to engineers?
Designers hand off accessibility by annotating it in the design file: focus order, accessible names, keyboard behavior, announcements and states. If it isn't in the spec, engineers have to guess, and guesses vary from screen to screen.
Our practice is a short annotation layer on each key frame: numbered focus order, the label for every icon button, what each overlay focuses first, and the text of every live announcement. Error copy and field labels come from the same source as the visible text, as described in our web form design best practices. Then test with a keyboard and a screen reader before each release. Automated checkers catch missing labels and contrast issues, but not broken focus flows.
