{"id":1028,"date":"2022-10-08T22:34:00","date_gmt":"2022-10-08T21:34:00","guid":{"rendered":"https:\/\/cerovac.com\/a11y\/?p=1028"},"modified":"2022-10-09T23:43:56","modified_gmt":"2022-10-09T22:43:56","slug":"accessible-accordion-in-native-android-applications-simple-solution","status":"publish","type":"post","link":"https:\/\/cerovac.com\/a11y\/2022\/10\/accessible-accordion-in-native-android-applications-simple-solution\/","title":{"rendered":"Accessible accordion in native Android applications &#8211; simple solution"},"content":{"rendered":"\n<p>I&#8217;ve just done some accessibility audits of native apps and had to fail WCAG Success Criterion 4.1.2 Name Role Value because accordion didn&#8217;t have proper semantics. I didn&#8217;t bothered checking the Android documentation about technical possibilities of marking expand collapse (like in ARIA), but I just felt it could be done technically.<\/p>\n\n\n\n<p>When I was later presenting the audit results I got a question from a developer if I have any tips on how to resolve it on native platform. I was honest about it and said that I will check. And this post is kind of a longer answer, hope it will help somebody someday.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">React Native solution<\/h2>\n\n\n\n<p>As I am way more experienced with React Native compared to Java And Kotlin I decided to check what are our options there. And I quickly found that <a rel=\"noreferrer noopener\" href=\"https:\/\/reactnative.dev\/docs\/accessibility#accessibilitystate\" target=\"_blank\">React Native supports some accessibility states with  accessibilityState attribute (opens in new window)<\/a>;<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>disabled,<\/li><li>selected,<\/li><li>checked,<\/li><li>busy,<\/li><li>expanded.<\/li><\/ul>\n\n\n\n<p>Perfect, I thought &#8211; if React Native supports it for both iOS and Android then it has to be also possible in native Android. So I tried to check some code of native Android parts used in React Native and discovered that they aren&#8217;t really using the best option (at least yet). I&#8217;ve checked GitHub issues and stumbled upon an <a href=\"https:\/\/github.com\/facebook\/react-native\/issues\/30841\" target=\"_blank\" rel=\"noreferrer noopener\">open issue that mentions the current downsides and also how to fix it properly (opens in new window)<\/a>;<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>The &#8220;expanded&#8221; accessibilityState for Android is currently faked by appending to the content description, rather than implemented correctly.\u00a0<\/p><cite>GitHub issue on current implementation<\/cite><\/blockquote>\n\n\n\n<p>Seems like they had some problems with some components, but I decided to test a proof of concept just to check it for myself. It worked well for my simple example, so I decided to publish it here. Please do test it before you use it in production;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import * as React from \"react\";\nimport { Text, View, TouchableHighlight } from \"react-native\";\n\nexport default function Accordion(props) {\n  console.log(\"props\", props);\n  const &#91;isOpen, setIsOpen] = React.useState(props.isActive);\n\n  const onPress = () => {\n    setIsOpen(!isOpen);\n  };\n\n  return (\n    &lt;View>\n      &lt;TouchableHighlight\n        accessibilityState={{ expanded: isOpen }}\n        accessibilityLabel={props.accTitle}\n        accessibilityRole=\"button\"\n        onPress={onPress}\n        style={{ paddingTop: 10, paddingBottom: 10, paddingLeft: 5 }}\n      >\n        &lt;View>\n          &lt;Text style={{ fontSize: 20 }}>{`${props.accTitle} ${\n            isOpen ? \"-\" : \"+\"\n          }`}&lt;\/Text>\n        &lt;\/View>\n      &lt;\/TouchableHighlight>\n      {isOpen ? (\n        &lt;View style={{ paddingTop: 10, paddingBottom: 10, paddingLeft: 5 }}>\n          &lt;Text>{props.content}&lt;\/Text>\n        &lt;\/View>\n      ) : null}\n    &lt;\/View>\n  );\n}<\/code><\/pre>\n\n\n\n<p>And yes, before you ask &#8211; I tried to use a Button but it just didn&#8217;t work. Seems like we have to enforce the semantics on a less optimal element. And beware &#8211; if you are planning to use this code on web it is missing the proper aria-expanded, so I would not use this for a web version.<\/p>\n\n\n\n<p>Anyway, I was happy with my TalkBack tests, the state was announced fine.<\/p>\n\n\n\n<p>If you want to play, please check the <a href=\"https:\/\/snack.expo.dev\/vwlfzL9f4\" target=\"_blank\" rel=\"noreferrer noopener\">working example on Expo snack (opens in new window)<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Native Android solution<\/h2>\n\n\n\n<p>I didn&#8217;t test it by running it in an app. At least not yet, but it seems like the platform really supports expand and collapse states out of the box.<\/p>\n\n\n\n<p>After digging in the documentation I stumbled upon <a href=\"https:\/\/developer.android.com\/reference\/android\/view\/accessibility\/AccessibilityNodeInfo.AccessibilityAction#ACTION_EXPAND\" target=\"_blank\" rel=\"noreferrer noopener\">ACTION_EXPAND that is available in AccessibilityAction and was added in API level 21 (opens in new window)<\/a>.<\/p>\n\n\n\n<p>I am not an Android developer, so I will borrow the following <a href=\"https:\/\/github.com\/facebook\/react-native\/issues\/30841#issue-800718248\" target=\"_blank\" rel=\"noreferrer noopener\">text from the React Native issue that I mentioned previously (opens in new window)<\/a>;<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>Expandable and Collapsible are unique in the Android Accessibility API, in that they are not represented as properties on the\u00a0<code>View<\/code>\u00a0or\u00a0<code>AccessibilityNodeInfo<\/code>, but are\u00a0<em>only<\/em>\u00a0represented as\u00a0<code>AccessibilityActions<\/code>\u00a0on the AccessibilityNodeInfo. This means that Talkback determines whether or not a node is &#8220;expandable&#8221; or &#8220;collapsible&#8221;, or potentially even both, by looking at the list of AccessibilityActions attached to the AccessibilityNodeInfo.<\/p><cite>GitHub issue on React Native describing Android implementation<\/cite><\/blockquote>\n\n\n\n<p>I think that this would have to make sense to a native Android developer and it looks like React Native will soon implement the &#8220;proper&#8221; expand and collapse in their native Android code as well.<\/p>\n\n\n\n<p>If you managed to fix it in your app, please let me know. Would be useful to share with others and make apps more accessible.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I had to fail an Android app in a recent WCAG audit because it&#8217;s expand\/collapse components didn&#8217;t have the semantics. On the review I got asked about possible solutions and here you go &#8211; hope it will help somebody make accordions on Android more accessible.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[503],"tags":[531,91,12,532,242,29,530],"class_list":["post-1028","post","type-post","status-publish","format-standard","hentry","category-native-mobile-apps-accessibility","tag-accordion","tag-android","tag-aria","tag-kotlin","tag-react-native","tag-wcag","tag-wcag-4-1-2"],"_links":{"self":[{"href":"https:\/\/cerovac.com\/a11y\/wp-json\/wp\/v2\/posts\/1028","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cerovac.com\/a11y\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cerovac.com\/a11y\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cerovac.com\/a11y\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/cerovac.com\/a11y\/wp-json\/wp\/v2\/comments?post=1028"}],"version-history":[{"count":0,"href":"https:\/\/cerovac.com\/a11y\/wp-json\/wp\/v2\/posts\/1028\/revisions"}],"wp:attachment":[{"href":"https:\/\/cerovac.com\/a11y\/wp-json\/wp\/v2\/media?parent=1028"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cerovac.com\/a11y\/wp-json\/wp\/v2\/categories?post=1028"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cerovac.com\/a11y\/wp-json\/wp\/v2\/tags?post=1028"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}