James Brooks
Whether you are just getting started with mobile application development or have a few years of experience under your belt, accessibility can be an often-overlooked implementation. As a novice in the field of mobile applications, I’ve found that, especially with React Native, it can begin as a deceptively simple process, but it can easily spiral into a complex and daunting task, especially when attempting to implement accessibility after a piece of software is already fully developed.
React Native is a framework used by developers to create mobile apps that work on both iOS and Android devices. It’s built on JavaScript and React, which are common web development tools, but it’s specifically designed for mobile. The key advantage of React Native is that it allows developers to write code once and use it across multiple platforms, saving time and effort compared to building separate apps for each operating system. This makes it a popular choice for companies looking to efficiently develop and maintain mobile apps.
Thankfully, new tools are constantly being added to the framework to make it easier than ever for developers of any skill level to add inclusive features to their applications and enormously improve their outreach.
Built-in Accessibility Properties
Sometimes, it’s as simple as using properties available to you in the React Native framework. With just a few simple keywords, you can make your application exponentially more useful for external accessibility tools.
The accessible Property:
When you add the accessible prop to a jsx tag and set it to true, it allows the entire element to be viewed by external software like a screen reader as a single focusable element. This is handy if you need the content of more than one tag to be read as one. For example:
const AccesibleTextComponent = () => {
return (
<View accessible={true}>
<Text>If you would like to</Text>
<Text>sign in, please</Text>
<Text>select the box below.</Text>
</View>
);
};
In the above example, the developer wants the entire paragraph, split between three Text tags to be read as one sentence (“If you would like to sign in, please select the box below.”). This formatting is not conventional for stacking text in a dynamic way in using html tags (you would most likely word-wrap an entire Text element), but for the sake of our example, this would allow the screen reader to give the user more understandable information about the focused component.
Additionally, interactive elements like TouchableOpacity automatically have accessibility set to “true” but can be set to false if it proves too difficult for certain programs to read it.
The accessibilityLabel Property:
In addition to allowing page elements and their children to be focusable, you can add additional comments for external screen readers to read aloud. Adding the accessibilityLabel with a string value will do just that. Simply add this as a property on an interactive element of an app to give additional details on its function or appearance. Here’s an example:
const SubmitButton = ({ onPress, formCompleted }) => {
return (
<TouchableOpacity accessible={true}>
{formCompleted && (
<Text onPress={onPress} accessibilityLabel="Submit Button">Submit</Text>
)}
</TouchableOpacity>
);
};
When the user has completed the relevant form, the text for the button will display. When this occurs with accessibility options, the user will hear “Submit Button” to cue the user to tap the focused submit button now that the form has been completed. Simple. Just a short consideration that allows the user to more easily navigate the product.
The accessibilityHint Property:
Like the accessibilityLabel, the accessibilityHint adds even more context to the user interface. On iOS, these hints can be turned off by the user, thereby allowing the user to control their level of context in the app-space.
const SubmitButton = ({ onPress, formCompleted }) => {
return (
<TouchableOpacity accessible={true}>
{formCompleted && (
<Text
onPress={onPress}
accessibilityLabel="Submit Button"
accessibilityHint=“Tap to submit your form”
>Submit</Text>
)}
</TouchableOpacity>
);
};
In this scenario, we’ve added some optional context that could help users navigate the application more quickly and easily.
The accessibilityLanguage Property:
A helpful tool to use when users are required to use or interpret words from other languages is the accessibilityLanguage property. This allows the screen reader to default to a set language pronunciation regardless of the source language. Here is a short example:
const Manufacturer = ({…props}) => {
return (
<View>
<Text
accessible={true}
accessibilityLanguage="en-US"
>
{props.companyName}
</Text>
</View>
);
};
This example component would function as a single manufacturer in a list and would display the company’s name in the text field. Since we are working in a global economy with company names of various languages, it would be helpful to the user (if they are a US English speaker) to hear the name in their native dialect instead of the source language.
There is currently no way to localize this setting to the user, but a package called ‘react-native-localize’ can be useful for automatically setting the app language to the user’s local language.
Install the library:
npm install react-native-localize
Import the library into your app and get user’s device language:
import { localize } from ‘react-native-localize'
const userLanguage = localize.getLang();
Use the newly created variable to allow the program to find and speak in the user’s native language and dialect:
const Manufacturer = ({…props}) => {
return (
<View>
<Text
accessible={true}
accessibilityLanguage={userLanguage}
>
{props.companyName}
</Text>
</View>
);
};
The accessibilityIgnoresInvertColors Property:
On iOS for accessibility options pertaining to low-vision or color-blindness you can overwrite the native color inversion for certain elements and components such as photos or color-coded diagrams by setting the value of this property on said element to “true”.
The accessibilityLiveRegion Property:
This property specifically modifies how the TalkBack application on Android alerts the user to app state changes on a given section of the document. You can set the value of this property to “none” to never alert user to changes, “polite” to add an alert to the end of a queue of alerts, or “assertive” if you would like the user notified of the change and interrupt all other TalkBack alerts.
The accessibilityRole Property:
This property has a diverse array of value options to notify the accessibility software of what specific functionality the relevant component has. A few examples include “scrollbar” which notifies the user of scrollbar functionality and “search” which indicates a search field.
A complete list of options can be found here.
The accessibilityState Property:**
Another feature included in the React Native framework is the accessibilityState property, which fulfills a similar responsibility to the accessibilityRole feature, but instead of roles, it indicates the state of the component it is used on. This option will typically receive a boolean value of true or false and translate this value into an audio cue (“disabled”, “selected”, “checked”, “busy” and “expanded”). These cues can be essential to navigating applications where the state of a certain element is crucial to the user experience. For example:
const UserForm = () => {
const \[checked, setChecked\] = useState(false);
const changeCheckedState = (userValue) => {
setChecked(userValue);
}
return (
<View>
<Text>Please Accept Terms and Conditions (IMPORTANT)</Text>
<Checkbox
value={checked}
onValueChange={handleCheckboxChange}
accessibilityLabel="Terms and Conditions Checkbox (IMPORTANT)"
accessibilityState={{ checked: checked }}
/>
{isChecked && <Text>You have accepted the terms and conditions.</Text>}
</View>
);
};
The user in this example will not be able to move the process along until they have accepted the Terms and Conditions. The accessibilityState property allows the user to have audible access to the current state of the checkbox and will cue the user when that state has changed.
The importantForAccessibility Property:
On Android devices, when two UI components overlap one another in your application and you need a way to distinguish between the two elements and avoid unpredictable outcomes, you can use importantForAccessibility to control whether these components trigger accessibility events or not.
If you place this property on your component and set the value to “auto”, “yes”, “no”, or “no-hide-descendants”. This will tell the reader whether to: Force default behavior, prioritize for accessibility alerts, hide for accessibility alerts or hide said component and the child elements. Here is an example:
const MoreDetail = ({articleContent, articleSummary}) = {
const \[showHideContent, setShowHideContent\] = useState(false);
const expandCollapse = () => {
setShowHideContent(!showHideContent)
};
return (
<View>
<Button
title={showHideContent ? 'Collapse' : 'Expand'}
onPress={expandCollapse}
<Text>{articleSummary}</Text>
{showHideContent && (
<View importantForAccessibility={showHideContent ? 'yes' : 'no'}>
<Text>{articleContent}</Text>
</View>
)}
</View>
);
};
Here we can see that the article can either be viewed in its summary form or by detailed ‘content’ once it is expanded using the ‘Expand’ or ‘Collapse’ button. This might cause some unwanted problems when using a screen reader and may even cause overlapping audio unless we give it some logic to help determine whether the content needs to be prioritized or not.
ARIA and React Native:
For those unfamiliar with ARIA (Accessible Rich Internet Applications), it is a technical specification created by the World Wide Web Consortium (W3C) to improve the accessibility of web pages through web language conventions and rules. These rules guide unfamiliar web developers in the ways of building more inclusive web applications.
The same conventions can be applied to mobile development. React Native contains a very similar structure to the web framework React.js, which draws its logical support from the web language JavaScript and presents the layout to users implementing the jsx html framework. If you would like to learn more about ARIA, you can read through the documentation here.
React Native strives to follow these same conventions and has a suite of ARIA options for developers to improve their application. These properties can be found in the React Docs [starting with aria-valuemax here.](https://reactnative.dev/docs/accessibility#aria-valuemax](https://reactnative.dev/docs/accessibility%23aria-valuemax)
Some highlights include aria-label and aria-labelledby, which, for those already familiar with ARIA’s conventions, are already built into html’s features. It may seem a small change, but when you are working with a mobile application it can be handy to have those features passed down to other html extensions like jsx.
Third-Party ARIA Library for React Native:
Alternatively, if your application requires a lot more hands-on work to achieve full ARIA compliance, you can use a third-party package to utilize a larger suite of ARIA features. The react-native-aria package provides more sophisticated solutions to complex accessibility scenarios.
Installing the library:
npm install react-native-aria
Importing individual features from the library:
import { useCheckbox } from "@react-native-aria/checkbox";
Documentation for the package can be found here.
Final Thoughts**
Making your application more accessible does not have to require complex programmatic software solutions. You can start by making minor changes to your application and even that small amount of effort goes a tremendously long way.
Embarking on the journey to make your mobile application more accessible for everyone can seem like a difficult extra step to your development process, but I hope by reading these few examples of simple implementation you are encouraged to build these features into your next app from the beginning.
In the long run, it can be an immeasurably worthwhile pursuit to make every app you create more easily accessible to all portions of the population. We talk about user experience when it comes to app design all the time and that should include every user.