Flutter

Accessibility with Flutter: the Basics of Semantics

I started at BAM as a React Native developer, and even then making accessibility applications was a struggle. Accessibility is a challenge in every step of the process - product, design and software development. Thankfully, I was already surrounded by developers who were concerned by this issue; check out this great beginner’s guide for react-native developers, written by Alexis Delage!

Transitioning to Flutter a few months ago meant that if I wanted to keep creating accessible apps, I almost needed to start from scratch. I became part of a project where accessibility wasn't initially a priority, providing me with a perfect opportunity to explore and learn how to integrate accessibility features into the app. Let's dive into the basics of making Flutter apps accessible together!

How to check my App for Accessibility?

Alexis Delage already explored the different ways to audit accessibility using screen readers. To summarize, you can use the Accessibility Inspector for iOS, or the Accessibility Scanner for Android.

To enhance our toolkit even further, I discovered a great property for Material based App: the ++code>showSemanticsDebugger++/code> from MaterialApp. By enabling the semantics debugger, you can ensure that your app is not only visually appealing but also accessible to all users, including those using assistive technologies!

What is happening? Where is my UI? 😱

Exactly, this is how a person who is blind might experience your app through a screen reader. This feature serves as an excellent segue for me to delve into how Flutter handles accessibility, providing a visual guide when you are developing. It's a crucial step in ensuring that your application is inclusive and accessible to all users, regardless of their abilities.

How to support accessibility with the flutter framework

The semantics tree

Semantics: the study of meanings in a language

Ultimately, accessibility in software engineering revolves around imbuing components with meaning, enabling various tools to grasp the essence of what's being presented. While the UI is primarily designed for visual interpretation, it's crucial to provide alternative ways for understanding your UI.

In Flutter, the UI structure is conceptualized as a Widget tree, where each widget can have a child (or children), referred to as nodes.

Alongside rendering its UI, Flutter also constructs a Semantics Tree. This tree plays a pivotal role for assistive technologies, search engines, and semantic analysis software, offering them the necessary context to comprehend the application's purpose and functionality.

Now, some of Flutter essential widgets are already designed to render a sound Semantics Tree. For example, here’s the source code (as of Flutter version 3.16) of the Button widget of Flutter.

The class used to annotate semantics properties is pretty well named: ++code>Semantics++/code>. Let’s see what we can do with this class and associates. 👀

The Semantics API

The ++code>Semantics++/code> class is used to annotate your widget with a comprehensive description and the necessary accessibility traits for a screen reader to work fine. Let’s see how my AppBar is read with an inspector:

Great! I have two buttons and I have no idea what their purpose is 😑

Indeed, how can one discern its purpose based solely on an icon and shape? It falls upon the developer to clarify this by adding a label, and this is where the Semantics widget comes into play. Fortunately for us, we consistently use the same rounded button widget throughout our app, making it easier to implement accessibility features uniformly!

I just need to add semantics Labels, and voilà ! Just a few lines of code, and every rounded button in my app is given a semantics Label. And as it is marked as required, I won’t ever forget it! Not so hard, wasn’t it?

But do I have to do this for every button, or worse for every widget ?? 😨

Fortunately no. As mentioned earlier, like every other good UI language, Flutter is smart, and its Semantics tree is particularly well constructed. Let’s take a look at a button without semantics, but this time with a label:

Great! I have all the information needed to understand this widget! But even with a pre-defined label, the semantics can be unclear in some cases, and wrapping the widget with Semantics can be important. Anyway, it is a good practice to ask oneself about the semantics of the widget, and label it accordingly.

There are a lot more semantics properties that you can explore to enhance screen reading. Among others, I use properties to define the states (++code>enabled++/code>, ++code>selected++/code>, ++code>toggled++/code>). But there are a lot more great objects to discover in this API.

Influencing the Semantics Tree

Flutter constructs a semantics tree, where each node may incorporate the semantic information of both itself and its children. This behavior can be influenced using ++code>MergeSemantics++/code>and ++code>ExcludeSemantics++/code> widgets. Essentially, these widgets allow you to specify whether a widget should include or exclude its children's semantics in its own node. This feature proves particularly beneficial in complex UIs, such as a large card filled with nested widgets, making it easier for screen readers to navigate and understand the content without overwhelming verbosity.

In this example, you'll notice a widget featuring a fake profile icon, which is accessible to screen readers, suggesting the potential to add a descriptive label.

However, I choose not to. My reasoning is that this widget doesn't enrich the semantic layer; it merely introduces an unnecessary step for the screen reader. Lacking substantive content or an ++code>onPressed++/code> action, it holds no genuine significance.


How can I remove it from the semantics tree? Well, ++code>ExludeSemantics++/code> seems to be a great candidate!

Be cautious: this action could inadvertently strip away important information, making parts of your app less accessible to users relying on assistive technologies. It's crucial to carefully consider the impact of these widgets on your app's accessibility features to ensure that no relevant information is lost.

Conclusion

Congratulations on making your app accessible to screen readers! It wasn't that difficult, was it? In my opinion, integrating the basics of accessibility with flutter from the early stages of development is so straightforward that it hardly adds any time to the development process. Moreover, I'm convinced that this approach not only encourages developers to delve deeper into the semantics of their views but also aids in structuring them more effectively later on.

Next steps: reduce animations

Animations are great, and you should definitely add some in your app to make it more lovable than ever. However, they can be too much for people with attention disorders. Most devices have accessibility settings to reduce motions (iOS) or disable animations (android). That seems to be a promising next topic for me to explore!

Développeur mobile ?

Rejoins nos équipes