Mobile app accessibility: a working checklist for small teams
A release by release accessibility checklist for small mobile teams: screen readers, text scaling, touch targets, contrast, icon labels and motion settings.

Turn on VoiceOver, open almost any small team's app, and swipe to the toolbar. Sooner or later you will hear the word "button" and nothing else. Someone drew a clean icon, nobody gave it a name, and for a person who relies on a screen reader that control is now a guess. Most accessibility problems I find in audits are like that one: small, ordinary and fixable in an afternoon.
This is the checklist I use, reduced to what a team of two to ten people can actually keep up with. It covers screen readers, text size, touch targets, contrast, labels, motion and forms, and it ends with a routine short enough to run before every release. None of it needs a specialist, although a specialist will always find more.
Why small teams are asking now
Two dates have moved accessibility up the agenda in Europe. In October 2023 the W3C published WCAG 2.2 as a Recommendation, adding new success criteria to the 2.1 set. And from 28 June 2025 the European Accessibility Act will apply to a range of consumer services, including e-commerce, consumer banking, e-books and passenger transport, and that includes the apps those services run on. Microenterprises that provide services are exempt, but the shop or bank you build for may well not be.
WCAG was written for the web, yet its success criteria are the yardstick most mobile audits use. When I say "passes" below, I mean the level AA criteria applied sensibly to a native screen.
Screen readers: VoiceOver and TalkBack
You only need a handful of gestures to test with either screen reader. Swipe right to move to the next element, swipe left to go back, double-tap anywhere to activate the element in focus. Set up the accessibility shortcut first so you can switch the reader on and off quickly: on iOS that's a triple-click of the side button, on Android it's holding both volume keys for a few seconds once TalkBack is assigned to the shortcut.
Then listen. Every interactive element should announce three things: a name ("Share"), a role ("button") and a state where it has one ("selected", "off"). Focus should move in the same order your eye reads the screen. A product card that takes five swipes to get through (image, title, price, rating, heart) usually reads better as one element with a combined label and a separate action for the heart.
Labels for icon buttons
Name the action, not the picture: "Share", not "Square with arrow". Leave the word "button" out of the label, since the role is already announced. Mark purely decorative images so the reader skips them.
Button(action: share) {
Image(systemName: "square.and.arrow.up")
}
.accessibilityLabel("Share")
IconButton(onClick = onShare) {
Icon(
imageVector = Icons.Filled.Share,
contentDescription = stringResource(R.string.share)
)
}
In Compose, a decorative icon gets contentDescription = null. Cross-platform frameworks have equivalents, such as
Flutter's Semantics widget and the accessibilityLabel prop in React Native. How faithfully a framework maps its
widgets to each platform's accessibility tree is one more question to add to the list in
choosing a cross-platform framework.
Text size: Dynamic Type and font scaling
On iOS, people choose a text size under Settings, Accessibility, Display & Text Size, Larger Text, and can switch on
Larger Accessibility Sizes for much bigger steps. If you use the system text styles, your text follows. Custom fonts
need to be scaled explicitly, with UIFontMetrics in UIKit or Font.custom(_:size:relativeTo:) in SwiftUI. On
Android, set text sizes in sp so the system font scale applies. Android 14 raised the maximum font scale to 200
percent and applies it nonlinearly, so large headings grow less than body text.
WCAG asks that text can be resized up to 200 percent without loss of content or functionality. In practice the text scales fine and the layout breaks: labels truncate to "Sett...", fixed-height rows clip the second line, and a horizontal row of three buttons runs off the screen. Let rows grow with their content, avoid fixed heights on anything that contains text, and switch side-by-side layouts to a vertical stack at the largest sizes. Xcode's Environment Overrides let you change the text size on a running simulator, which makes this check fast.
Touch targets
Apple's Human Interface Guidelines ask for a hit area of at least 44 by 44 points. Android's accessibility guidance recommends at least 48 by 48 dp. WCAG 2.2 added a lower floor for the web, 24 by 24 CSS pixels, but on a phone the platform numbers are the ones to meet.
The visible icon can be smaller than the target. A 20 point glyph inside a 44 point tappable frame looks light and is still easy to hit. Material components in Compose already reserve the minimum touch area; a custom clickable box does not, unless you give it a minimum size. Watch spacing as well: two large targets pressed edge to edge produce the same mis-taps as two small ones.
Contrast, and color on its own
WCAG's contrast minimum is 4.5:1 for normal text and 3:1 for large text, which it defines as at least 18 point, or 14 point bold. Icons, input borders, focus rings and the parts of a control you need to see to use it should reach 3:1 against what's next to them. The usual failures are pale gray placeholder text, light gray hint text under a field, and white text on a brand color that looked fine on a calibrated monitor. Check every pair in both light and dark appearance; dark mode tends to fail on secondary text rather than primary.
Color must not carry meaning on its own. A form field that turns red on error also needs an icon or a line of text saying what went wrong, and a chart needs labels or patterns as well as hues.
Motion
iOS has Reduce Motion, and Android has Remove animations in its accessibility settings. When either is on, replace slides, zooms and parallax with simple fades or no transition at all, and stop looping background animations. In SwiftUI you can read the setting from the environment:
@Environment(\.accessibilityReduceMotion) private var reduceMotion
Many system transitions adapt to these settings on their own. Custom animations, especially decorative ones on onboarding and empty screens, are where apps forget. Those first-run screens deserve a full screen reader and motion pass of their own, since they are often the least tested and the most animated; I went through their structure in onboarding flows people actually finish.
Forms and feedback
Forms are where screen reader users most often get stuck, because the visual cues that guide everyone else are silent. Give every field a visible label that stays on screen while someone types. A placeholder that disappears on the first keystroke is not a label, and screen readers handle it inconsistently.
When validation fails, say what went wrong and how to fix it ("Enter a date after today", not "Invalid input"),
place the message next to the field, and make sure it gets spoken. On iOS you can post an announcement with
UIAccessibility.post(notification: .announcement, argument:); on Android, a live region on the error text gets it
read when it appears. Set the right keyboard and autofill hints (textContentType on iOS, autofill hints on
Android), which saves typing for everyone and a great deal of effort for people using switch access or dictation.
And be careful with timers: a one-time code that expires before someone has found the field is a locked door.
The checklist
| Area | Check | Passes when |
|---|---|---|
| Labels | Every icon button and image control has a name | The reader says what it does, never just "button" |
| Order | Focus order follows the visual order | No jumps between columns or back to the top |
| Grouping | Cards and list rows read as one unit | One swipe per item, with extra actions available |
| State | Toggles, tabs and checkboxes announce state | "Selected", "on" or "off" is spoken |
| Text size | Largest size on both platforms | Nothing clipped, no truncated button labels |
| Targets | Tappable areas measured | 44x44 pt on iOS, 48x48 dp on Android |
| Contrast | New colors checked in light and dark | 4.5:1 text, 3:1 large text and controls |
| Color alone | Errors and status use more than color | Icon or text carries the same meaning |
| Motion | Reduce Motion and Remove animations on | No sliding or zooming transitions, no loops |
| Forms | Fields have visible labels and clear errors | Errors are announced and say how to fix them |
A routine for every release
This takes about half an hour for a typical feature release, and less once the team is used to it.
- Run the automated checks first. On iOS, Xcode 15 added
performAccessibilityAudit()for UI tests, which flags missing labels, clipped text and contrast problems on the screens your tests visit. On Android, run Lint and Google's Accessibility Scanner app on the changed screens. - Do a screen reader pass on every screen the release touched. Alternate platforms each release so both get attention over time.
- Set the largest text size and walk the same screens again.
- Check contrast for any color added since the last release, in both appearances.
- Turn on Reduce Motion or Remove animations and repeat the main flow once.
- File what you find as ordinary bugs with a severity. A missing label on the pay button blocks the release; a slightly awkward reading order on a settings screen can wait a sprint.
Automated checks catch the mechanical problems. The manual passes find the rest, especially order, grouping and anything that only makes sense when you hear it. Neither replaces people who use these features every day. If the budget allows one paid research session a year, spend it with screen reader and switch access users; they will find problems no checklist describes. More on testing and build practice lives in the mobile development track.
If you do only one thing before your next release, make it this: switch on the screen reader, close your eyes on the checkout or sign-up screen, and try to finish. Whatever stops you is the first ticket.
Keep reading

Building a small Android test device lab on a budget
How to pick Android test phones by role, buy them refurbished, keep them charged and connected over Wi-Fi, and decide which to update and which to freeze.

Design systems for small app teams: start smaller than you think
How a small app team can build a design system that lasts: tokens first, a dozen components, notes in the design file, clear names and a first month plan.

App store screenshots that explain the app in five seconds
How to plan app store screenshots that work at search size: what the first three must show, how to write captions, and how to handle languages and dark mode.