Skip to main content
Logo Appt Light

An Accessible App. Where to start?

Making your app accessible to everyone: where do you start? Below are the main steps that will help you make your app usable for the widest possible group of people, including people with disabilities.

April 22, 2024

Testing for accessibility with someone who is blind

It can seem very complicated and even intimidating when you delve into the vast amount of information on digital accessibility. How do you incorporate all those guidelines, insights and code examples into an app? To get you started, we have listed the six most important steps for you.

  1. Use a screen reader!

  2. Offer textual alternatives.

  3. Make it clear what the purpose is.

  4. Make sure text can be resized.

  5. Provide sufficient contrast.

  6. Show focus and offer a logical order.

Below is a detailed explanation of each step. Finally, we explain how you can test whether it works as intended.

Note that this list is not exhaustive and will not make your app fully accessible. But is meant to make the biggest possible difference through a few simple steps.

1. Use a screen reader!

To properly test whether your app is accessible, it pays to learn how to use a screen reader

A screen reader is mainly used by visually impaired people. However, by optimising your app for this, you ensure that a much larger group of people can use your app. Users of voice, keyboard and switch controls will also benefit, and you automatically take into account a lot of success criteria from the WCAG.

This makes the screen reader the ideal tool to test for accessibility. But it can take some getting used to. It all works a little differently from what you are used to. With the ScreenReader app, you learn all the gestures and possibilities as you go.

2. Offer textual alternatives

Do all buttons have a clear label? Do icons, images, graphics, among others, have a textual alternative?

Make sure alternative text is available for all content without text. These include images, icons and graphs. Describe what can be seen. People who are blind have this description read aloud through their screen reader. Alternative text can also be useful for anyone who is unsure about the meaning of the content.

You do this by setting an accessibility label. You can see how to do this for your app in the example below.

On Android, you can use the contentDescription attribute to set an accessibility label.

You can also pass any kind of Span for greater control over pronunciation. For example, you can set a language by using LocaleSpan.

If another element is used to display the label, you can link the label by using the labelFor attribute.

// Set accessibility label
element.contentDescription = "Appt"

// Set accessibility label in Dutch language
val locale = Locale.forLanguageTag("nl-NL")
val localeSpan = LocaleSpan(locale)

val string = SpannableString("Appt")
string.setSpan(localeSpan, 0, string.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)

element.contentDescription = localeSpan

// Link visual label to field
textView.setLabelFor(R.id.editText)

3. Make clear what the purpose is

Is it clear what action can be performed? 

Set a name. The name is used for identification. Setting a name allows tools such as voice control to perform targeted actions.

Set accessibility name

On Android, the contentDescription property is used as accessibility name.

element.contentDescription = "Appt"

Set a role. With the role "button", it is clear that an action takes place on activation. With the role "link", it is clear that you are directed to another location. Setting a role makes it clear to tool users what they can do.

Set accessibility role

On Android, you can use the setAccessibilityDelegate method of ViewCompat to get a reference to AccessibilityNodeInfoCompat. This object contains many useful accessibility related methods.

You can set a role using the setRoleDescription method. However, we recommend using the setClassName method over setRoleDescription to support multilingual roles. For example, set Button::class.java.name if an element behaves like a button. The role will be set to Button in English, and to its respective translation in other languages.

You can indicate a heading by using the setHeading method. ViewCompat also contains a convenience method: setAccessibilityHeading.

ViewCompat.setAccessibilityDelegate(
    element,
    object : AccessibilityDelegateCompat() {
        override fun onInitializeAccessibilityNodeInfo(
            host: View,
            info: AccessibilityNodeInfoCompat
        ) {
            super.onInitializeAccessibilityNodeInfo(host, info)

            // Custom
            info.roleDescription = "Custom role"

            // Button
            info.className = Button::class.java.name

            // Heading
            info.isHeading = true

            // Image
            info.className = ImageView::class.java.name
        }
    }
)

// Convenience method
ViewCompat.setAccessibilityHeading(view, true)

Set a value. For a checkbox, the value is "selected" or "not selected". For a volume control, the value can be "50%". By setting a value, this can also be passed textually to tools.

Set accessibility value

Android has limited support to provide a dedicated accessibility value for assistive technologies. The AccessibilityNodeInfoCompat object contains a couple of methods, such as the setChecked method.

Unfortunately the desired value is often not available. If your desired value is not included, you can append it to the contentDescription attribute.

ViewCompat.setAccessibilityDelegate(
    element,
    object : AccessibilityDelegateCompat() {
        override fun onInitializeAccessibilityNodeInfo(
            host: View,
            info: AccessibilityNodeInfoCompat
        ) {
            super.onInitializeAccessibilityNodeInfo(host, info)
            info.isChecked = true
        }
    }
)

element.contentDescription = "Name (Value)"

4. Make sure text can be resized

Is it possible to display text in a larger font size? Does text remain readable with a larger font size?

Ensure that the text in your app supports resizing. Users specify their preferred font size in the system settings. Text in your app should resize according to the preferred font size. This is especially important for visually impaired users because otherwise they might not be able to read the text. Text should not be abbreviated with dots.

Support text scaling

On Android, you can use Scale-independent Pixels to scale text. This unit ensures that the user's preferences are taken into account when determining the font size. We recommend to define the textSize in your styles to make sure it's the same everywhere.

<style name="Widget.TextView">
    <item name="android:textSize">18sp</item>
</style>

Ensure that all content on the screen remains readable even with the largest font. Content should be readable without having to scroll in two directions. Because the text is displayed larger, it can push other elements off the screen. Ensure content can still be reached, for example, by scrolling vertically.

Prevent text truncation

On Android, you can avoid text truncation by removing all instances of android:maxLines from your app. You should also avoid using fixed values for any heights or widths and instead use wrap_content where possible.

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Avoid text truncation" 
    android:maxLines="REMOVE" />

5. Provide sufficient contrast

Does text have sufficient contrast relative to the background? Do elements on the screen have sufficient contrast against each other and in relation to the background?

Ensure that the content on the screen has a contrast of at least 3:1 with the surrounding colour. Think of graphic elements such as icons, buttons and input fields.

Ensure that the contrast ratio between the text colour and background colour is at least 4.5:1. For bold and large text, a ratio of 3:1 is sufficient.

By maintaining these ratios, visually impaired and colour blind users can usually read the text well. In addition, this makes an app easier for everyone to use, for example outside in the sun.

6. Show focus and offer a logical order

Is it clear where the focus is? Is the order in which the focus moves logical?

Ensure that elements focused by assistive technologies are clearly indicated. Focus is often shown by placing a box around the element. Make sure that the placement is correct and that the colour is clearly visible. For apps it is not possible to adjust the colour of the frame. However, it is possible to give elements a different background colour when they have focus.

Add accessibility focus indicator

On Android, you can adjust colors when an element receives focus. However, it's not possible to change the focus indicator of assistive technologies. Users can adjust their preferences in the system settings of Android.

You can use a ColorStateList to change colors based on the element state. An element moves into the state_focused whenever it receives focus.

The code sample below shows how to change the background color of a button on focus.

<!-- selector.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/focused" android:state_focused="true" />
    <item android:drawable="@color/default" />
</selector>

<!-- layout.xml -->
<Button
    android:id="@+id/button"
    android:background="@drawable/selector">
</Button>

Ensure assistive technologies use a logical focus order when navigating. The order of navigating a screen is usually from left to right, from top to bottom. Make sure assistive technologies use an equivalent focus order. 

Adjust order for keyboard

On Android, you can use several focus properties to modify the keyboard focus order.

<View
    android:id="@+id/notFocusable"
    android:focusable="false"/>

<EditText
    android:id="@+id/field1"
    android:focusable="true"
    android:nextFocusForward="@+id/field2"
    android:nextFocusDown="@+id/field3"
    android:nextFocusRight="@+id/field2"/>

<EditText
    android:id="@+id/field2"
    android:focusable="true"
    android:nextFocusForward="@+id/field3"
    android:nextFocusDown="@+id/field4"/>

<EditText
    android:id="@+id/field3"
    android:focusable="true"
    android:nextFocusForward="@+id/field4"/>

<EditText
    android:id="@+id/field4"
    android:focusable="true"/>

Adjust order for assistive technologies

On Android, you can set the accessibility order in XML, or modify the accessibility order in code. You can use the android:accessibilityTraversalAfter and android:accessibilityTraversalBefore properties in XML. Or you can use the setAccessibilityTraversalBefore and setAccessibilityTraversalAfter methods in code.

header.setAccessibilityTraversalBefore(R.id.description)
list.setAccessibilityTraversalAfter(R.id.description)

Move accessibility focus

On Android, you can send an AccessibilityEvent of the type TYPE_VIEW_FOCUSED to move the focus of assistive technologies to a specific view. The view must be focusable for this event to take effect.

fun focus(view: View) {
    view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)
}

Testing

You can test most of the steps with the Accessibility Scanner app and Xcode's Accessibility Inspector. You can also detect contrast issues automatically with these. another option is to take a screenshot of an app to determine the colour codes and calculate the contrast. This can be done with WebAIM's Contrast Checker, for example.

In addition, check that it works properly by using the screen reader.

To test whether text scaling is properly supported, set a large font size. You can do this on a phone under the accessibility settings.

Questions?

By following these steps, you will make your app accessible to a very large group of people. Anything missing? Is something not quite clear? Let us know in the slack channel of Appt.

Feedback?

Let us know!