Skip to content

Accessibility Behavior

Maciej Jastrzebski edited this page Oct 8, 2022 · 11 revisions

Methods of testing:

  • iOS: using Accessibility Inspector (in iOS mode!) on iOS simulator
  • Android: using TalkBack on Android emulator

<Text> component

<Text> behavior in iOS

Component Screen reader Label Value Traits Identifier Hint User Input Label
<Text>Hello!</Text> Hello! Hello ! (none) Static Text (none) (none) Hello !
accessible={true} accessibilityRole="text" Hello! Hello ! (none) Static Text (none) (none) Hello !
accessible={true} Hello! Hello ! (none) Static Text (none) (none) Hello !
accessible={false} (ignored) (ignored) (ignored) (ignored) (ignored) (ignored) (ignored)
accessibilityRole="text" Hello! Hello ! (none) Static Text (none) (none) Hello !
accessibilityRole="none" Hello! Hello ! (none) (none) (none) (none) Hello !

Findings:

  • iOS behaves the same for when accessible={true} or when prop is not specified
  • iOS behaves the same for when accessibilityRole="text" or when prop is not specified
  • iOS ignores element when accessible={false}
  • changing accessibilityRole to "none" removes Static Text trait, but view is still readable by screen reader

<Text> behavior in Android

Component Screen reader
<Text >Hello!</Text> Hello!
accessible={true} accessibilityRole="text" Hello!
accessible={true} Hello!
accessible={false} Hello!
accessibilityRole="text" Hello!
accessibilityRole="none" Hello!
importantForAccessibility="no" (ignored)
importantForAccessibility="no-hide-descendants" (ignored)

Findings:

  • Android accessible props does not affect TalkBack screen reader behaviour
  • Android accessibilityRole props does not affect TalkBack screen reader behaviour
  • Android ignores element if importantForAccessibility value "no" or "no-hide-descendants"

<Text> handling recommendations

  • assume default accessible value of true
  • assume default accessibilityRole of text
  • assume none role when accessibilityRole="none"
  • assume excluded from accessibility when accessible={false} (based on iOS semantics)
  • assume excluded from accessibility role when importantForAccessibility="no" or importantForAccessibility="no-hide-descendants" (based on Android semantics)

<TextInput> component

<TextInput> behavior in iOS

Component Screen reader Label Value Traits Identifier Hint User Input Label
<TextInput defaultValue="Hello" /> Hello (none) Hello (empty) (none) (none) Hello
accessible={true} Hello (none) Hello (empty) (none) (none) Hello
accessible={false} Hello (none) Hello (empty) (none) (none) Hello
accessibilityRole="search Hello - search field (none) Hello Search Field (none) (none) Search Field
accessibilityRole="none" Hello (none) Hello (empty) (none) (none) Hello
editable={false} Hello - not enabled (none) Hello Not enabled (none) (none) Hello

Findings:

  • iOS ignores accessible={false} attribute, it behaves the same as default and true value
  • iOS ignores accessibilityRole="none" the elements behaves the same as without role attribute
  • iOS reacts to accessibilityRole="search" by reading the "serach field" trait name
  • iOS reacts to editable={false} by reading the "not enabled" trait name

<TextInput> behavior in Android

Component Screen reader
<TextInput defaultValue="Hello" /> Hello - edit box - double tap to edit text - double tap and hold to long press
accessible={true} Hello - edit box - double tap to edit text - double tap and hold to long press
accessible={false} Hello - edit box - double tap to edit text - double tap and hold to long press
accessibilityRole="search Hello - edit box - double tap to edit text - double tap and hold to long press
accessibilityRole="none Hello - edit box - double tap to activate - double tap and hold to long press
editable={false} Hello - edit box - disabled
importantForAccessibility="no" (ignored)
importantForAccessibility="no-hide-descendants" (ignored)

Findings:

  • Android ignores accessible={false} attribute, it behaves the same as default and true value
  • Android ignores accessibilityRole="search" the elements behaves the same as without role attribute
  • Android slight alters the read text when accessibilityRole="none", it says "double tap to activate" instead of "to edit text"

<TextInput> handling recommendations

  • assume "search" role when accessibilityRole="search"
  • assume excluded from accessibility role when importantForAccessibility="no" or importantForAccessibility="no-hide-descendants" (based on Android semantics)
  • assume accessibilityState disabled when editable={false}
  • consider assuming excluded from accessibility when accessible={false} (based on other elements behavior) TextInput behavior might be a bug
  • consider assuming implicit ARIA role of textbox when no explicit role is provided (based on the fact that Android reads "edit box" hint

<View> component

<View> behavior in iOS

Component Screen reader Label Value Traits Identifier Hint User Input Label
<View /> (ignored) (ignored) (ignored) (ignored) (ignored) (ignored) (ignored)
accessible={true} Description for element unavailable (none) (none) (empty) (none) (none) (Empty Array)
accessible={false} (ignored) (ignored) (ignored) (ignored) (ignored) (ignored) (ignored)
accessibilityRole="button" (ignored) (ignored) (ignored) (ignored) (ignored) (ignored) (ignored)
accessibilityRole="none" (ignored) (ignored) (ignored) (ignored) (ignored) (ignored) (ignored)
onPress={() => {}} (ignored) (ignored) (ignored) (ignored) (ignored) (ignored) (ignored)
accessible={true} accessibilityRole="button" Button (ignored) (ignored) Button (ignored) (ignored) (ignored)

Findings:

  • iOS ignores element when accessible={false} or when prop is not specified
  • iOS notices element when accessible={true}
  • iOS notices accessibilityRole only when accessible={true}
  • setting accessibilityRole or onPress alone does not affect iOS

<View> behavior in Android

Component Screen reader
<View /> (ignored)
accessible={true} (nothing, but focusable)
accessible={false} (ignored)
accessibilityRole="button" (ignored)
accessibilityRole="none" (ignored)
onPress={() => {}} (ignored)
accessible={true} accessibilityRole="button" Button - double tap to activate
importantForAccessibility="yes" (ignored)

Findings:

  • Android ignores element when accessible={false} or when prop is not specified
  • Android notices element when accessible={true} (becomes focusable)
  • Android notices accessibilityRole only when accessible={true} (reads the role)
  • setting accessibilityRole or onPress alone does not affect Android
  • Android ignores element if importantForAccessibility value "yes"

<View> handling recommendations

  • assume default accessible value of false
  • assume excluded from accessibility when accessible={false} or default
  • assume has default role "none" when accessible={true}

Accessibility State

Control Screen Reader Label Value Traits Identifier Hint User Input Labels
<View accessible={true} accessibilityRole="checkbox" accessibilityState={{ checked: true }} /> "checkbox, checked" (none) checkbox, checked (empty) (none) (none) (empty array)
<View accessible={true} accessibilityRole="checkbox" accessibilityState={{ checked: 'mixed' }} /> "checkbox, mixed" (none) checkbox, mixed (empty) (none) (none) (empty array)
<View accessible={true} accessibilityRole="checkbox" accessibilityState={{ checked: false }} /> "checkbox, not checked" (none) checkbox, not checked (empty) (none) (none) (empty array)
"checkbox" (none) checkbox (empty) (none) (none) (empty array)
"checkbox" (none) checkbox (empty) (none) (none) (empty array)
Clone this wiki locally