State Descriptions on Android
Learn what state descriptions are, why they’re important for accessibility and how you can use them on older versions of Android.
State descriptions are a relatively new addition to the accessibility toolbox on Android, having been added in Android 11 (API 30). It’s a dedicated property used to describe a UI component’s current state.
Before this API, we had to overload the content description to provide this extra information:
Now, we can keep the state description separate:
In this post, we’ll look at the state description property and how we can use it in both Jetpack Compose UIs as well as traditional View-based systems.
When do I need a state description?
A state description is helpful when a UI component changes visually to express state.
Built-in components like CheckBox
, RadioButton
and Switch
are all well-known to accessibility services. The service can query these components and present their state to the users automatically:
RadioButton
and Switch
enjoy similar functionality. Google TalkBack will present these with “selected”/“not selected” and “on”/“off” as the respective state descriptions.
For custom widgets, icons or badges, there are no such instrinsic properties. Accessibility services don’t know about our custom volume indicator or microphone badge, so it used to be necessary to bake information about the state into the content description.
With the state description property, we can instead keep our content description short and focused.
State descriptions in Jetpack Compose UI
In this example, we’re using the Slider
component to represent min/max price filters. If we check with TalkBack though, it’s using the default state description which isn’t very helpful; we want it to show the price.
State descriptions can be set in Compose UI using Modifier.semantics
. Here, we’re updating the default description so that it tells us what price is currently selected:
Slider(
value = sliderPosition,
onValueChange = { sliderPosition = it },
modifier = Modifier.semantics {
val money = (sliderPosition * 100).toInt()
stateDescription = "£$money"
}
)
This works with the latest version of Talkback (12.1), even on older versions of Android (I tested on Android 10, prior to the introduction of the state description API). Jetpack Compose UI works all the way back to Android 5.1 (API 21) so this is great news.
State descriptions in a View-based UI system
In a View-based system, we can use the ViewCompat
API from AppCompat. It uses view tags to backport support all the way back to Android 4.4 (API 19)!
val localizedDesc = "On" // TODO: localize it..!
ViewCompat.setStateDescription(micView, localizedDesc)
This lets us set a state description on any View which accessibility services (like TalkBack) should use.
What’s next?
It’s pretty cool that this new property has been backported so far back in both View and Compose UIs. If you haven’t seen it yet, I’d recommend watching this video from Shailen Tuli about “Conveying state for Accessibility”:
⚠️ One place that hasn’t worked as expected is with Seekbar. Star this issue to get updates on this bug!
Let me know if you have comments or questions!
Thanks Jolanda and Caren for the reviews and help with filing the bug!