arrowAll projects
Rijksoverheid, Municipality of Rotterdam, Municipality of Ridderkerk
3 months

Designing accessible native & web apps for governments

It's 2023, and we still haven't figured out how to make apps (or technology in general) accessible for everyone, regardless of origin, ability, etc. For the last two years, I've helped out making various web- and native apps more accessible to use.

Designing accessible native & web apps for governments header image

Legislation

Since September 2020, the Dutch government made it mandatory by law that all websites of municipalities and governments are WCAG 2.1 A + AA accessible. Since June 2021, this also applies to native mobile apps. In 2025, all public services need to be fully accessible according to the European Accessibility Act.

The facts: 50% of all Dutch people use at least one accessibility setting on their phone

According to an independent study by Dutch Stichting Appt, a foundation that’s working on educating and helping Dutch product people ship accessible apps, more than half of the 18 million Dutch population use at least one accessibility feature on their phone. Nearly 20% of users use multiple accessibility features. Of those who use accessibility features, approximately 35% choose alternative text sizes.

In addition, there are at least 1.3 million Dutch people with some form of color blindness, who need to be taken into account during the design process. There are also more than 6,000 Dutch people who have the text on their screen read aloud because they can’t (or can’t sufficiently) see it themselves.

These figures are much higher than often expected, which is reason enough to prioritize accessibility when designing and developing an application.

My experience with designing accessible apps

Designing my first native mobile app with accessibility in mind

The first project I worked on where we spent a lot of time on accessibility was a small native mobile app (Flutter) for the municipality of Ridderkerk. The goal of the application was to have all important and essential information about the municipality at hand with a set of informative views.

We also created an integration with the Overheid.nl API which shows everything that's happening in your neighborhood on a map, whether it's an officially requested party or a renovation in your street.

Ridderkerk app

During the design process of the app, I did a lot of research on what to consider from a product design perspective to be WCAG 2.1 A + AA compliant. I learned a lot about testing color contrast, designing for color blindness, and working with iOS VoiceOver and Android Talkback. A central part of the app was a map with a set of POIs with all the announcements. During the design process, I learned that maps are really hard to make accessible and that you should have an alternative with the same functionality.

Checking color contrast

While working on this app, we started to notice more and more that most accessibility features are great to have for people without a disability as well and that designing for accessibility doesn’t just mean trying to include people with disabilities, it’s actually about creating solutions that work better for everyone, everywhere. Using the personas and visuals below made it easier to understand this for everyone.

Accessibility personas

Apple and Google offer a lot of native APIs and possibilities that are helping designers and engineers out when creating accessible apps, however, when working in Flutter for cross-platform development as we did, you’ll lose a lot of the stuff you otherwise got for free. Because of this, we worked with an auditor in various iterations to see and learn how accessible the app was in practice, and this experience was truly insightful as we learned a lot about how to group components and elements with landmarks, and how we sometimes should explicitly define focus order.

Designing an accessible educational web app in 36 languages for the Ministry of Social Affairs and Employment of the Rijksoverheid

The second product with a focus on A11Y I worked on was an education-focused web application (desktop, tablet, mobile) for the Dutch Ministry of Social Affairs and Employment. Together with them, we worked on a new version of their educational and training software that’s being used to let immigrants learn and practice for the exam when they want to apply for Dutch citizenship.

Rijksoverheid KNS app

The application should be designed leveraging the existing visual style and brand guides from the Rijksoverheid, be WCAG 2.1 A + AA accessible, and support usage in 36 languages, ranging from Dutch to languages like German (which has a lot of really long words), various forms of Arabic (right to left instead of our Western left to right writing orientation), Chinese, Russian, Sinhalese, and many more.

Language switcher KNS app

We did a lot of research on typography, and the support for non-western languages, and learned a lot of things that we leveraged while designing:

  • The need for fallback fonts like Noto Sans for non-western languages, how we could automatically use the right fonts using UTF-8, and how SF Pro and Noto Sans don’t even have the characters to support languages like Hindi, Sinhalese, and Punjabi
  • We learned about characters looking smaller when writing Arabic scripture in fonts like Noto Sans, and that we had to change our design and define rules for this
  • How we had to work with mixing Arabic and Western languages, for example when calling out the name of the Dutch king in the lessons, or when using West-Arabic numbers (which are the same as our Western numbers 0 1 2 3 4 5 6 7 8 9 0) instead of East-Arabic, and when using the Gregorian calendar for date notation.
  • We learned about directionals and mirroring of UI components, like input fields that got mirrored and for example show dropdown chevrons on the left side of a field, and how Arabic languages always show the checkboxes or radio button icons on the right side.
KNS app in Arabic

Using the existing visual style, I iteratively mapped the complete flow, designed the first version of the product, and led the design process later on as another designer worked on the actual mocks and specs. As we didn’t have all translations of the final content available yet, couldn’t use unknown external Figma plugins that automatically translate all our mocks in all the languages because of security reasons, and didn’t have the time and resources to build a plugin that we could run locally ourselves, we decided to only design the most important states and screens in the available dummy Arabic and Chinese content, use dummy translations for English and German we created ourselves, and manually design for the various languages and test our designs.

During the complete design process, we kept accessibility in mind using contrast checkers, color blindness simulators, and more and used Figma auto-layout and constraints to quickly create alternative screen sizes and test our designs on various new and old devices, as a lot of our users non-Western would probably use our application using older, small Android smartphones.

KNS app on multiple devices
Redesigning and making an existing app that’s being used to get a hand on sexual harassment accessible

The municipality of Rotterdam was already using the StopApp, a native iOS (Swift) and Android (Kotlin) app that gives citizens the ability to mark places they got sexually harassed. In this way, citizens help out with mapping the places where the most harassment occurs. The app is actively helping out the municipality and local police to get a hand on this problem.

The application needed a full redesign and rebuild, as no work had been done on it for almost 4 years. The municipality received a new visual brand and web-focused design system which we used as a starting point. I led the design process of applying the web-focused design system to components that felt at home on native mobile and redesigning all screens, states, and mocks, while the product design intern I was guiding did most of the actual pixel work.

StopApp

As part of the redesign and front-end rebuild of the app, we also worked on making the design accessible. As all colors, type, and other primitives were mostly defined and accessible out of the box (size, contrast, color blindness, etc.) we could use more time to design rules for font scaling and dynamic type sizing, designing an accessible alternative for the map feature that’s the central part of the app, and working on alternative layouts of the report forms that were still intuitive to use and clear to digest when people used there phones in landscape.

StopApp in landscape in Figma

Our biggest issues with applying the guidelines

After working on a Flutter app, a native iOS and Android app, and a web-based project, I’m still no expert on designing accessible products and applying the WCAG, and I probably still just know about the top of a very large (but interesting) iceberg. However, I noticed that I was front-running with practical knowledge in my team, so I decided to help my team out.

From my experience working at an agency for governments and municipalities, I learned that designing and building accessible products is hard. The biggest problems I came across:

Being short on budget makes it hard to run user tests

Often, there isn’t enough budget dedicated to performing proper usability tests. It’s a shame because it would help us find a lot of bugs and make the product better. Besides making the product better, it would also be educational: even when trying to be really empathic, I would’ve never guessed that people who are bad of sight or almost blind and use voice-over often set their font size at the smallest size possible. This feels counter intuitive because as characters become smaller, they’re even harder to read — however, on the flip side, the smaller the characters, the more UI elements can be shown on the screen, making it way easier to navigate scrollviews using VoiceOver or talkback (as seen in this video by accessibility foundation Appt).

Practical application of the guidelines

Another problem is that the WCAG documentation on W3.org is a lot of information. This makes it hard to digest and learn all the guidelines for designers and engineers that are just starting out. Also, the rules often are clear about what you have to comply with, but often lack some practical application on how to comply in practice.

Except for captions and images of text, text can be resized without assistive technology up to 200 percent without loss of content or functionality.

— Success Criterion 1.4.4 Resize text

For example, when checking out Success Criterion 1.4.4 Resize text above, it’s clear that when building an iOS app, you have to design, spec, and build rules for dynamic font sizing so users can scale up or down the font size of the button component you created. However when the button component also has an icon, what should be the desired outcome? Should it scale, or not? And what if it takes up a lot of space? Should you remove it?

When checking out existing government apps that should already be accessible, or using native Apple apps, we’d expect to find great examples for these questions, but as seen below, a lot of apps aren’t really optimized yet for these situations.

WhatsApp and Apple Maps with AX-5 font sizes

Example question on icon-scaling:

  • Question: Should we make icons scale up and down as well when designing and implementing dynamic font sizing?
  • Answer: It depends…
    • If you’re using icons in a tabbar where you can’t wrap content easily, you should scale your icons up or down, but also define a min- and max-size.
    • If you’re using an icon inside of a button or table-row component, scaling it up and down would be desired, but all UI components next to the button or table-row can impact this decision as well because wrapping the icon and button-label when using enlarged text, could make the rest of the screen really hard to use

Example question on designing features using a (Google, Apple or Mapbox) map integration:

  • Question: Features using map integrations aren’t accessible for screen readers like iOS VoiceOver. The WCAG says that you should provide (textual) alternatives for these features and that mechanisms to bypass a block of a map should be available, but when is the alternative feature you create truly a viable alternative?
  • Answer: It depends…

For these and a lot of other questions, it was really hard to find the right answer: on one hand because accessibility on native mobile is quite new, on the other hand because the answer to questions isn’t clear because it always depends on the specific situation you’re in.

To help find an answer in these situations, I wrote and often updated an internal Wiki for myself and my team and gave a presentation, sharing all sorts of resources, knowledge based on past experience of building specific features, and answers to questions we already tackled in a project.

Teachning about accessibility

Helping out and educating my team

In this section of this casestudy, I’m highlighting some of the things I learned and wrote about in the wiki while working on the projects mentioned above:

Color contrast and color blindness

About 1.3 million Dutch people have some form of color blindness. As a result, they see colors differently than others or may not be able to properly perceive contrasts between different colors. All colors used must have a minimum contrast ratio (difference between foreground and background) that’s high enough, which can be checked with tools de contrast checker in Sip or the accessibility tools by Stark:

Text size Text weight AA Minimum contrast ratio AAA Minimum contrast ratio
Up to 17pt Regular 4.5:1
14pt and larger Bold 3:1 4.5:1
18pt and larger Any 3:1 4.5:1
Icons 3:1

In addition, it’s important that all interface elements can be distinguished from each other as well by someone who is color blind. I mostly focus on Deuteranopia and Monochromacy as these are the most common forms of color blindness, but of course, I’m always checking out my designs through the lens of other forms of color blindness using tools like Sim Daltonism.

A great example of where color-blind people can misinterpret a UI if it isn’t tested with a color-blindness simulator is the design of a radio button component in a test that also should indicate if the result is right or wrong. As shown I worked on figuring out how to indicate the state and result using more primitives than only color for the Rijksoverheid app below.

Simulating color blindness

In this design, we see that nothing should be indicated by one type of formatting like only using color or change of size, as the WCAG states as well in guidelines 1.3.3 Sensory Characteristics (Level A) and 1.4.1 Use of Color (Level A). Another example of this is the map in the Ridderkerk app: we use a color and icon to distinguish specific POIs from each other. We flip selected POIs in terms of color settings and make them larger. If we had only used color to distinguish POI categories from each other, a color-blind person would not have been able to perceive this correctly.

Map with POIs
Dynamic font sizing

It’s possible to adjust the font size from the accessibility settings of a phone. The study done by Appt learned us that adjusting text size is the second most used accessibility setting on phones in the Netherlands, right behind dark mode, with 35% of the studied phone users using larger or smaller text.

When checking out often-used apps, like WhatsApp and Apple Maps, we learn that alternative type size, and especially the 175% sizes and above, is extremely hard to get right, and sometimes feels like you have to make one trade-off after another.

Support for adjusting type size works outside of the box on Android (at least in Flutter), just as with websites and web apps in browsers. To reach this on iOS, you have to apply dynamic type sizing and support the mandatory 200% alternative font size. For when you’re not using Apple's default pre-defined type settings with SF Pro / Text, Apple offers the UIFontMetrics API to connect your own defined type to the default properties, and still get the ability to let your app scale type up or down based on the users' OS settings.

I started by trying to set up alternative primitives in pixels or percentages for all the text styles we got defined for our apps in Figma, but quickly realized this wasn't the way. UIFontMetrics automatically scales and re-calculates the right percentages for scaling font sizes, line height, tracking, etc based on every dynamic size that users can select. Large title and Title 1 will have a smaller percentage scale factor than Body to keep the app looking normal for as long as possible.

Text styles overview

To accommodate for this, I learned that it’s way easier to just map the defined text styles in Figma to the text styles in Xcode or using the overview in the Dynamic Size docs, compile the app you’re working on, find out where things break, and collaborate with an engineer on defining min- and max-size rules for certain text-styles, or specific type in specific components like the labels of tabs in a bottom-tabbar. A lot of things will break initially (especially when you're also supporting landscape and have to support the small 4-inch iPhone SE which will be updated to the latest iOS version that’s required to support in 2025) but it’s a great starting point to fix things.

Broken screens on landscape

Example: the label in a search bar can have the same defined text style as other places of your app, but because of the limited space it has, it can’t grow in size indefinitely. A fallback for this in most UI components is to just wrap the text, but when creating a search input using UIKit of SwiftUI, engineers will probably often use UITextField which can only contain one line of text, whereas a UITextView can wrap its content. When a search bar is built on top of a UITextField, not setting up a max-size for the text will make it unreadable.

Setting up a solid system with scaling rules for your text, containers, icons, etc. will help in creating an app that’s also usable for people who need to use tiny or large text.

StopApp with AX font sizes supported
Landscape

When you need to comply with guideline 1.3.4 Orientation (Level AA), all views of your app have to support portrait and landscape orientation unless a specific orientation is essential.

To comply with this, I learned that designing the most important views in landscape, and setting up clear guidelines on how to deal with safe-area’s on devices (looking at the notches and homebars of fancy smartphones nowadays…) is often enough to collaborate with an engineer on supporting alternative orientations in the complete app.

A couple of interesting things to notice when adjusting your design and code to support landscape orientation:

  • Navbars and tabbars should take up less vertical space to accommodate for the lower height.
  • Navbars and tabbars often take care of the safe-area’s on a device when designing portrait-oriented apps, and you don’t really have to watch out for them when designing. In landscape you need to support an alternative grid as the notch or dynamic island shouldn’t conflict with your content, but the backgrounds of sections in your app should go underneath them.
  • Statusbars get hidden in landscape on iOS, but most OEMs on Android still show them on top of your navbar component and have alternative safe-area’s per device. The homebar on iOS still has the same safe-area, but some Android phones place their onScreen controls (home, back, multi-tasking) on top of your UI with a transparent backdrop layer.
  • Especially on iOS, landscape support can automatically make use of alternative UIKit SizeClasses which is great to make use of the extra horizontal real-estate and for example show elements dual-column where
  • It’s really important to prototype the layout and behavior of your app for views where users can open a keyboard. As there’s already limited vertical real-estate and the keyboard is quite large, the area of your app you can use becomes much smaller. Especially when combined with large AX-3, -4, or -5 dynamic font sizing, things will start to break down quickly
StopApp landscape fixed
Video & audio

Video and audio are difficult accessibility topics as they’re not accessible by default, and both need to get complete transcriptions for every video or audio file that’s being used in the app so it can be read by screen readers like VoiceOver. Video also should get subtitles or captions. Text that’s displayed in the video should also be called out in the transcriptions and subs if it’s relevant for the user.

Autoplay of videos should always be turned off, or at least the audio should be muted, and there should be a clear play button to begin watching the video from the start.

Captions KNS video
Screen readers

After watching this 2019 WWDC session on Writing Great Accessibility Labels I learned that default labeling for screen readers sometimes isn’t sufficient, and it’s important to think carefully about the text being read by VoiceOver and Talkback and where necessary rewrite it for your engineers to implement it. As somebody using a screen reader can’t see nor understand the context of the selected component, additional information or context might be required.

To write ‘alternative screen reader copy’, I set up a little internal writing system for documenting it inside Figma so our engineers would understand how to implement it:

  • Label = regular font-weight
  • Trait = italics, ideally in a heavier font-weight
  • {copy} = possible copy that’s already in the UI

A couple of examples in the StopApp where we wrote alternative copy to provide more context for people using a screen reader (see numbers in the image below):

  1. The information button at the top left would get the following VoiceOver copy by default: Icon, button. This doesn’t provide enough context, and for a blind person it doesn’t matter the button only has an icon. We wrote the following alternative: Information, button.
  2. The button at the top right with the icon and the text “bel 112” (”call 112”, the Dutch emergency phone number) got accidentally translated as Icoon, bel honderdtwaalf, knop (Icon, call one hundred and twelve, button) which of course is wrong. To prevent this, we rewrote it to Bel een een twee, knop (Call one one two, button)
  3. The buttons “Hier!” (”Here!”) and “Andere locatie” (”Other location”) give enough context for people who can clearly see and interact with the content on the screen. However, when you’re blind, Hier, knop (Here, button) or Andere locatie, knop (Other location, button) don’t give the right context. We rewrote this to Melding doen op huidige locatie, knop (Report at current location, button) and Melding doen op andere locatie, knop (Report in another location, button).
  4. In the form, there’s a header with the copy “Wat is er gebeurd?” (”What happened?”) with a set of selection buttons. Again: for people who can see the context of the complete form, the combination of label and selection buttons speaks for itself. For people who can’t see this context, we made it a bit more clear by giving an extra instruction with the screen reader: {Wat is er gebeurd?}, selecteer een of meerdere opties ({What happened?}, select one or more options).
  5. For switches, we also indicate the state and we give an extra suggestion what the user can do with it: Agree, switch, off, double tap to switch
  6. For inputs, we indicate the state. For example, whether they are editable or not.
Screenreader highlights
Maps

As mentioned above, map implementations (Google Maps, Apple Maps, Mapbox) are often not accessible and are pretty expensive to make accessible. When your map isn’t accessible, it’s mandatory to create an alternative that offers all of the functionality that can also be used with the map feature. Based on how the map is being used, you can design the alternative.

The map in the Ridderkerk app has a lot of different types of POIs with their own color and icon, which open a detailview with a specific report. Within the map, you can also navigate to your own current location and two pre-entered preferred locations on the map. This allows the map to be focused on various places, and it’s possible to quickly see what is happening near the location. As an alternative, we created a list view with the featured locations and a list of all POI categories. Tapping one of the options shows a new view with all the associated reports - thus offering the same functionality the map offers but in an accessible way.

Map alternative for Ridderkerk

The map in the StopApp is used to place a marker and communicate the specific location of an incident in the city. Using a list feature as an alternative like we did for the Ridderkerk app doesn’t offer the correct functionality in this case. As an alternative to the map feature in the StopApp, we created a textual search using the Google Maps API, so users can search for and select a specific address.

By creating these alternatives, we still made it possible for people using accessibility features like a screen reader to use the complete functionality of the app.

Map alternative for StopApp

Accessibility Bundle Names

A bonus takeaway I learned when researching common mistakes when building accessible apps, is that developers can set the CFBundleSpokenName or Accessibility Bundle Name on iOS, a replacement for the app name when using a screen reader.

The Accessibility Bundle Name makes sure that the application name is understandable to everyone. A funny (but bad) example of this going wrong is the Dutch ING Banking app which is called “Bankieren” (Dutch for “Banking”). People with good eyesight can recognize from the app icon that this is the ING Banking app, and not ABN AMRO Bank, however, their Accessibility Bundle Name is the same, so when using VoiceOver, it’s impossible to know which app is which.

Accessibility Bundle Name ING and ABN AMRO Banks

Credits

This project couldn’t exist without these wonderful people I collaborated with over the course of the project:

frankvanzwieteren - Profile picture
Frank

PM

renswijnmalen - Profile picture
Rens

Lead engineer

larsmoesman - Profile picture
Lars

iOS engineer

patrickvandegraaf - Profile picture
Patrick

Android engineer

robinheij - Profile picture
Robin

Front-end engineer

dennisklein - Profile picture
Dennis

Product designer

irisoldengarm - Profile picture
Iris

Design intern

Project info