Principles for improving app accessibility

Some people who use Android devices have different accessibility needs than others. To assist a given group of the population who shares an accessibility need, the Android framework provides the ability for developers to create an accessibility service, which presents apps' content to them and operates apps on their behalf.

Android provides several system accessibility services, including the following:

  • TalkBack: Helps people who have low vision or are blind. Announces content through a synthesized voice, and performs actions on an app in response to user gestures.
  • Switch Access: Helps people who have motor disabilities. Highlights interactive elements, and performs actions in response to the user pressing a button. Allows for controlling the device using only 1 or 2 buttons.

In order to help people with accessibility needs use your app successfully, your app should follow the best practices described on this page, which build upon the key guidelines described in Make apps more accessible.

Each of the following best practices can further improve your app's accessibility:

Label elements
Users should be able to understand the content and purpose of each interactive and meaningful UI element within your app.
Use or extend system widgets
Build off of the view elements that the framework includes, rather than creating your own custom views. The framework's view and widget classes already provide most of the accessibility capabilities that your app needs.
Use cues other than color
Users should be able to clearly distinguish between categories of elements in a UI. To do so, use patterns and position, along with color, to express these differences.
Make media content more accessible
Try to add descriptions to your app's video or audio content so that users who consume this content don't need to rely on entirely visual or aural cues.

Label elements

It's important to provide users with useful and descriptive labels for each interactive UI element in your app. Each label should explain the meaning and purpose of a particular element. Screen readers such as TalkBack can announce these labels to users who rely on these services.

In most cases, you specify a given UI element's description in the layout resource file that contains this element. Although you usually add labels using the contentDescription attribute, as explained in the guide to making apps more accessible, there are several other labeling techniques to keep in mind, as described in the following sections.

Editable elements

When labeling editable elements, such as EditText objects, it's helpful to show text that gives examples of valid input in the element itself, in addition to making this example text available to screen readers. In these situations, you can use the android:hint attribute, as shown in the following snippet:

<!-- The hint text for en-US locale would be
     "Apartment, suite, or building". -->
   android:hint="@string/aptSuiteBuilding" ... />

In this situation, the View object should have its android:labelFor attribute set to the ID of the EditText element. For more details, see the section describing how to label pairs of elements where one describes the other.

Pairs of elements where one describes the other

It's common for a given EditText element to have a corresponding View object that describes the content that users should enter within the EditText element. On devices that run Android 4.2 (API level 17) or higher, you can indicate this relationship by setting the View object's android:labelFor attribute.

An example of labeling such element pairs appears in the following snippet:

<!-- Label text for en-US locale would be "Username:" -->
   android:id="@+id/usernameLabel" ...
   android:labelFor="@+id/usernameEntry" />

   android:id="@+id/usernameEntry" ... />

<!-- Label text for en-US locale would be "Password:" -->
   android:id="@+id/passwordLabel" ...
   android:labelFor="@+id/passwordEntry" />

   android:inputType="textPassword" ... />

Elements in a collection

When adding labels to the elements of a collection, each label should be unique. That way, the system's accessibility services can refer to exactly one on-screen element when announcing a label. This correspondence lets users know when they've cycled through the UI or when they've moved focus to an element that they've already discovered.

In particular, you should include additional text or contextual information in elements within reused layouts, such as RecyclerView objects, so that each child element is uniquely identified.

To do so, set the content description as part of your adapter implementation, as shown in the following code snippet:


data class MovieRating(val title: String, val starRating: Integer)

class MyMovieRatingsAdapter(private val myData: Array<MovieRating>):
        RecyclerView.Adapter<MyMovieRatingsAdapter.MyRatingViewHolder>() {

    class MyRatingViewHolder(val ratingView: ImageView) :

    override fun onBindViewHolder(holder: MyRatingViewHolder, position: Int) {
        val ratingData = myData[position]
        holder.ratingView.contentDescription = "Movie ${position}: " +
                "${ratingData.title}, ${ratingData.starRating} stars"


public class MovieRating {
    private String title;
    private int starRating;
    // ...
    public String getTitle() { return title; }
    public int getStarRating() { return starRating; }

public class MyMovieRatingsAdapter
        extends RecyclerView.Adapter<MyAdapter.MyRatingViewHolder> {
    private MovieRating[] myData;

    public static class MyRatingViewHolder extends RecyclerView.ViewHolder {
        public ImageView ratingView;
        public MyRatingViewHolder(ImageView iv) {
            ratingView = iv;

    public void onBindViewHolder(MyRatingViewHolder holder, int position) {
        MovieRating ratingData = myData[position];
        holder.ratingView.setContentDescription("Movie " + position + ": " +
                ratingData.getTitle() + ", " + ratingData.getStarRating() +
                " stars")

Groups of related content

If your app displays several UI elements that form a natural group, such as details of a song or attributes of a message, arrange these elements within a container, which is usually a subclass of ViewGroup. Set the container object's android:screenReaderFocusable attribute to true, and each inner object's android:focusable attribute to false. In doing so, accessibility services can present the inner elements' content descriptions, one after the other, in a single announcement. This consolidation of related elements helps users of assistive technology discover the information that's on the screen more efficiently.

The following snippet contains pieces of content that relate to one another, so the container element, an instance of ConstraintLayout, has its android:screenReaderFocusable attribute set to true, and the inner TextView elements each has its android:focusable attribute set to false:

<!-- In response to a single user interaction, accessibility services announce
     both the title and the artist of the song. -->
    android:id="@+id/song_data_container" ...

        android:id="@+id/song_title" ...
        android:text="@string/my_song_title" />
        android:text="@string/my_songwriter" />

Because accessibility services announce the inner elements' descriptions in a single utterance, it's important to keep each description as short as possible while still conveying the element's meaning.

Custom group label

If desired, you can override the platform's default grouping and ordering of a group's inner element descriptions by providing a content description for the group itself.

The following snippet shows an example of customized group description:

<!-- In response to a single user interaction, accessibility services
     announce the custom content description for the group. -->
    android:id="@+id/song_data_container" ...

        android:id="@+id/song_title" ...

        <!-- Content ignored by accessibility services -->
        android:text="@string/my_song_title" />

        <!-- Content ignored by accessibility services -->
        android:text="@string/my_songwriter" />

Nested groups

If your app's interface presents multi-dimensional information, such as a day-by-day list of festival events, use the android:screenReaderFocusable attribute on the inner group containers. This labeling scheme provides a good balance between number of announcements needed to discover the screen's content and the length of each announcement.

The following code snippet shows one method of labeling groups inside of larger groups:

<!-- In response to a single user interaction, accessibility services
     announce the events for a single stage only. -->
    android:id="@+id/festival_event_table" ... >

        <!-- UI elements that describe the events on Stage A. -->


        <!-- UI elements that describe the events on Stage B. -->


Headings within text

Some apps use headings to summarize groups of text that appear on screen. If a particular View element represents a heading, you can indicate its purpose for accessibility services by setting the element's android:accessibilityHeading attribute to true.

Users of accessibility services can choose to navigate between headings instead of between paragraphs or between words. This flexibility improves the text navigation experience.

Accessibility pane titles

In Android 9 (API level 28) and higher, you can provide accessibility-friendly titles for a screen's panes. For accessibility purposes, a pane is a visually distinct portion of a window, such as the contents of a fragment. In order for accessibility services to understand a pane's window-like behavior, you should give descriptive titles to your app's panes. Accessibility services can then provide more granular information to users when a pane's appearance or content changes.

To specify the title of a pane, use the android:accessibilityPaneTitle attribute, as shown in the following snippet:

<!-- Accessibility services receive announcements about content changes
     that are scoped to either the "shopping cart view" section (top) or
     "browse items" section (bottom) -->
     android:accessibilityPaneTitle="@string/shoppingCart" ... />

     android:accessibilityPaneTitle="@string/browseProducts" ... />

Decorative elements

If an element in your UI exists only for visual spacing or visual appearance purposes, set its android:contentDescription attribute to "null".

If your app supports only the devices that run Android 4.1 (API level 16) or higher, you can instead set these purely decorative elements' android:importantForAccessibility attributes to "no".

Extend system widgets

Key point: When you design your app's UI, use or extend system-provided widgets that are as far down Android's class hierarchy as possible. System-provided widgets that are far down the hierarchy already have most of the accessibility capabilities that your app needs. It's easier to extend these system-provided widgets than to create your own from the more generic View, ViewCompat, Canvas, and CanvasCompat classes.

If you must extend View or Canvas directly, which might be necessary for a highly customized experience or a game level, see Make custom views more accessible.

This section describes how to implement a special type of Switch called TriSwitch. A TriSwitch object works similarly to a Switch object, except that each instance of TriSwitch allows the user to toggle among 3 possible states.

Extend from far down the class hierarchy

The Switch object inherits from several framework UI classes in its hierarchy:

↳ TextView
  ↳ Button
    ↳ CompoundButton
      ↳ Switch

It's best for the new TriSwitch class to extend directly from the Switch class. That way, the Android accessibility framework provides most of the accessibility capabilities that the TriSwitch class needs:

  • Accessibility actions: Inform the system how accessibility services emulate each possible user input that's performed on a TriSwitch object. (Inherited from View.)
  • Accessibility events: Inform accessibility services about every possible way that a TriSwitch object's appearance can change when the screen refreshes or updates. (Inherited from View.)
  • Characteristics: Details about each TriSwitch object, such as the contents of any text that it displays. (Inherited from TextView.)
  • State information: A description of a TriSwitch object's current state, such as "checked" or "unchecked". (Inherited from CompoundButton.)
  • Text description of state: A text-based explanation of what each state represents. (Inherited from Switch.)

This aggregate behavior, from Switch and its superclasses, is nearly the desired behavior for TriSwitch objects. Therefore, your implementation can focus on expanding the number of possible states from 2 to 3.

Define custom events

When you extend a system widget, you likely change an aspect of how users interact with that widget. It's important to define these interaction changes so that accessibility services can update your app's widget as if the user interacted with the widget directly.

A general guideline is that, for every view-based callback that you override, you also need to redefine the corresponding accessibility action by overriding ViewCompat.replaceAccessibilityAction(). In your app's tests, you can validate the behavior of these redefined actions by calling ViewCompat.performAccessibilityAction().

How this principle would work for TriSwitch objects

Unlike an ordinary Switch object, tapping a TriSwitch object cycles through 3 possible states. Therefore, the corresponding ACTION_CLICK accessibility action needs to be updated:


class TriSwitch(context: Context) : Switch(context) {
    // 0, 1, or 2.
    var currentState: Int = 0
        private set

    init {

    private fun updateAccessibilityActions() {
        ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK,
            action-label) {
            view, args -> moveToNextState()

    private fun moveToNextState() {
        currentState = (currentState + 1) % 3


public class TriSwitch extends Switch {
    // 0, 1, or 2.
    private int currentState;

    public int getCurrentState() {
        return currentState;

    public TriSwitch() {

    private void updateAccessibilityActions() {
        ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK,
            action-label, (view, args) -> moveToNextState());

    private void moveToNextState() {
        currentState = (currentState + 1) % 3;

Use cues other than color

To assist users with color vision deficiencies, use cues other than color to distinguish UI elements within your app's screens. These techniques could include using different shapes or sizes, providing text or visual patterns, or adding audio- or touch-based (haptic) feedback to mark the elements' differences.

Figure 1 shows two versions of an activity. One version uses only color to distinguish between two possible actions in a workflow. The other version uses the best practice of including shapes and text in addition to color to highlight the differences between the two options:

Figure 1: Examples of creating UI elements using color only (left) and using color, shapes, and text (right)

Make media content more accessible

If you're developing an app that includes media content, such as a video clip or an audio recording, try to support users with different types of accessibility needs in understanding this material. In particular, we encourage you to do the following:

  • Include controls that allow users to pause or stop the media, change the volume, and toggle subtitles (captions).
  • If a video presents information that is vital to completing a workflow, provide the same content in an alternative format, such as a transcript.

Additional resources

To learn more about making your app more accessible, see the following additional resources:


Blog posts