Accessibility

Ensuring apps are accessible to a broad range of users is an essential part of building a high-quality app. Applications that are poorly designed create barriers to people of all ages. The UN Convention on the Rights of Persons with Disabilities states the moral and legal imperative to ensure universal access to information systems; countries around the world enforce accessibility as a requirement; and companies recognize the business advantages of maximizing access to their services.

We strongly encourage you to include an accessibility checklist as a key criteria before shipping your app. Flutter is committed to supporting developers in making their apps more accessible, and includes first-class framework support for accessibility in addition to that provided by the underlying operating system, including:

Large fonts
Render text widgets with user-specified font sizes
Screen readers
Communicate spoken feedback about UI contents
Sufficient contrast
Render widgets with colors that have sufficient contrast

Details of these features are discussed below.

Inspecting accessibility support

In addition to testing for these specific topics, we recommend using automated accessibility scanners:

  • For Android:
    1. Install the Accessibility Scanner for Android
    2. Enable the Accessibility Scanner from Android Settings > Accessibility > Accessibility Scanner > On
    3. Navigate to the Accessibility Scanner ‘checkbox’ icon button to initiate a scan
  • For iOS:
    1. Open the iOS folder of your Flutter app in Xcode
    2. Select a Simulator as the target, and click Run button
    3. In Xcode, select Xcode > Open Developer Tools > Accessibility Inspector
    4. In the Accessibility Inspector, select Inspection > Enable Point to Inspect, and then select the various user interface elements in running Flutter app to inspect their accessibility attributes
    5. In the Accessibility Inspector, select Audit in the toolbar, and then select Run Audit to get a report of potential issues
  • For web:
    1. Open Chrome DevTools (or similar tools in other browsers)
    2. Inspect the HTML tree containing the ARIA attributes generated by Flutter.
    3. In Chrome, the “Elements” tab has a “Accessibility” sub-tab that can be used to inspect the data exported to semantics tree

Large fonts

Both Android and iOS contain system settings to configure the desired font sizes used by apps. Flutter text widgets respect this OS setting when determining font sizes.

Font sizes are calculated automatically by Flutter based on the OS setting. However, as a developer you should make sure your layout has enough room to render all its contents when the font sizes are increased. For example, you can test all parts of your app on a small-screen device configured to use the largest font setting.

Example

The following two screenshots show the standard Flutter app template rendered with the default iOS font setting, and with the largest font setting selected in iOS accessibility settings.

Default font setting
Default font setting
Largest accessibility font setting
Largest accessibility font setting

Screen readers

For mobile, screen readers (TalkBack, VoiceOver) enable visually impaired users to get spoken feedback about the contents of the screen and interact with the UI by using gestures on mobile and keyboard shortcuts on desktop. Turn on VoiceOver or TalkBack on your mobile device and navigate around your app.

To turn on the screen reader on your device, complete the following steps:

  1. On your device, open Settings.
  2. Select Accessibility and then TalkBack.
  3. Turn ‘Use TalkBack’ on or off.
  4. Select Ok.

To learn how to find and customize Android’s accessibility features, view the following video.

  1. On your device, open Settings > Accessibility > VoiceOver
  2. Turn the VoiceOver setting on or off

To learn how to find and customize iOS accessibility features, view the following video.

For web, the following screen readers are currently supported:

Mobile browsers:

  • iOS - VoiceOver
  • Android - TalkBack

Desktop browsers:

  • macOS - VoiceOver
  • Windows - JAWs & NVDA

Screen readers users on web must toggle the “Enable accessibility” button to build the semantics tree. Users can skip this step if you programmatically auto-enable accessibility for your app using this API:

import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';

void main() {
  runApp(const MyApp());
  SemanticsBinding.instance.ensureSemantics();
}

Windows comes with a screen reader called Narrator but some developers recommend using the more popular NVDA screen reader. To learn about using NVDA to test Windows apps, check out Screen Readers 101 For Front-End Developers (Windows).

On a Mac, you can use the desktop version of VoiceOver, which is included in macOS.

On Linux, a popular screen reader is called Orca. It comes pre-installed with some distributions and is available on package repositories such as apt. To learn about using Orca, check out Getting started with Orca screen reader on Gnome desktop.


Check out the following video demo to see Victor Tsaran, using VoiceOver with the now-archived Flutter Gallery web app.

Flutter’s standard widgets generate an accessibility tree automatically. However, if your app needs something different, it can be customized using the Semantics widget.

When there is text in your app that should be voiced with a specific voice, inform the screen reader which voice to use by calling TextSpan.locale. Note that MaterialApp.locale and Localizations.override don’t affect which voice the screen reader uses. Usually, the screen reader uses the system voice except where you explicitly set it with TextSpan.locale.

Sufficient contrast

Sufficient color contrast makes text and images easier to read. Along with benefitting users with various visual impairments, sufficient color contrast helps all users when viewing an interface on devices in extreme lighting conditions, such as when exposed to direct sunlight or on a display with low brightness.

The W3C recommends:

  • At least 4.5:1 for small text (below 18 point regular or 14 point bold)
  • At least 3.0:1 for large text (18 point and above regular or 14 point and above bold)

Building with accessibility in mind

Ensuring your app can be used by everyone means building accessibility into it from the start. For some apps, that’s easier said than done. In the video below, two of our engineers take a mobile app from a dire accessibility state to one that takes advantage of Flutter’s built-in widgets to offer a dramatically more accessible experience.

Testing accessibility on mobile

Test your app using Flutter’s Accessibility Guideline API. This API checks if your app’s UI meets Flutter’s accessibility recommendations. These cover recommendations for text contrast, target size, and target labels.

The following example shows how to use the Guideline API on Name Generator. You created this app as part of the Write your first Flutter app codelab. Each button on the app’s main screen serves as a tappable target with text represented in 18 point.

final SemanticsHandle handle = tester.ensureSemantics();
await tester.pumpWidget(MyApp());

// Checks that tappable nodes have a minimum size of 48 by 48 pixels
// for Android.
await expectLater(tester, meetsGuideline(androidTapTargetGuideline));

// Checks that tappable nodes have a minimum size of 44 by 44 pixels
// for iOS.
await expectLater(tester, meetsGuideline(iOSTapTargetGuideline));

// Checks that touch targets with a tap or long press action are labeled.
await expectLater(tester, meetsGuideline(labeledTapTargetGuideline));

// Checks whether semantic nodes meet the minimum text contrast levels.
// The recommended text contrast is 3:1 for larger text
// (18 point and above regular).
await expectLater(tester, meetsGuideline(textContrastGuideline));
handle.dispose();

You can add Guideline API tests in test/widget_test.dart of your app directory, or as a separate test file (such as test/a11y_test.dart in the case of the Name Generator).

Testing accessibility on web

You can debug accessibility by visualizing the semantic nodes created for your web app using the following command line flag in profile and release modes:

flutter run -d chrome --profile --dart-define=FLUTTER_WEB_DEBUG_SHOW_SEMANTICS=true

With the flag activated, the semantic nodes appear on top of the widgets; you can verify that the semantic elements are placed where they should be. If the semantic nodes are incorrectly placed, please file a bug report.

Accessibility release checklist

Here is a non-exhaustive list of things to consider as you prepare your app for release.

  • Active interactions. Ensure that all active interactions do something. Any button that can be pushed should do something when pushed. For example, if you have a no-op callback for an onPressed event, change it to show a SnackBar on the screen explaining which control you just pushed.
  • Screen reader testing. The screen reader should be able to describe all controls on the page when you tap on them, and the descriptions should be intelligible. Test your app with TalkBack (Android) and VoiceOver (iOS).
  • Contrast ratios. We encourage you to have a contrast ratio of at least 4.5:1 between controls or text and the background, with the exception of disabled components. Images should also be vetted for sufficient contrast.
  • Context switching. Nothing should change the user’s context automatically while typing in information. Generally, the widgets should avoid changing the user’s context without some sort of confirmation action.
  • Tappable targets. All tappable targets should be at least 48x48 pixels.
  • Errors. Important actions should be able to be undone. In fields that show errors, suggest a correction if possible.
  • Color vision deficiency testing. Controls should be usable and legible in colorblind and grayscale modes.
  • Scale factors. The UI should remain legible and usable at very large scale factors for text size and display scaling.

Learn more

To learn more about Flutter and accessibility, check out the following articles written by community members: