<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Fanny Demey</title>
    <description>The latest articles on DEV Community by Fanny Demey (@fannydemey).</description>
    <link>https://dev.to/fannydemey</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F610078%2F1bca1e00-deda-4130-9527-8e7ca2c25825.jpeg</url>
      <title>DEV Community: Fanny Demey</title>
      <link>https://dev.to/fannydemey</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fannydemey"/>
    <language>en</language>
    <item>
      <title>Best practices to build accessible apps with Jetpack Compose</title>
      <dc:creator>Fanny Demey</dc:creator>
      <pubDate>Mon, 02 Aug 2021 07:10:59 +0000</pubDate>
      <link>https://dev.to/fannydemey/best-practice-to-build-accessible-apps-with-jetpack-compose-1l5n</link>
      <guid>https://dev.to/fannydemey/best-practice-to-build-accessible-apps-with-jetpack-compose-1l5n</guid>
      <description>&lt;p&gt;Hello! &lt;br&gt;
Here you are! You have finally decided to take a look at what it takes to make your android application accessible for people with visual impairment. First, that's great news ! You'll see that it's a rewarding path that you are about to take. &lt;/p&gt;

&lt;p&gt;Today I'm going to share with you a list of best practices to make your app accessible specifically for people who are blind. I will show you how to do that with Jetpack Compose. &lt;/p&gt;
&lt;h2&gt;
  
  
  How does Talkback work ?
&lt;/h2&gt;

&lt;p&gt;Talkback is the screen reader on android used by blind or low vision users. &lt;/p&gt;

&lt;p&gt;Here are several gestures that you can perform anywhere on the screen, that allows you to navigate through each elements:&lt;/p&gt;

&lt;p&gt;➡️: swipe to the right to go to next element&lt;/p&gt;

&lt;p&gt;⬅️: swipe to the left to go to previous element&lt;/p&gt;

&lt;p&gt;↕️: swipe up and down on the screen or swipe down and up, will open a menu. In this menu you can configure swipe up / swipe down gesture, for example: Navigation between headers, speech rate, read letter by letter (useful to read a password for example).&lt;/p&gt;

&lt;p&gt;⬇️ or ⬆️: swipe up or down allows you to perform an action that you configured with the previous gesture.&lt;/p&gt;

&lt;p&gt;👆: single tap on an element on the screen will give the focus to this element.&lt;/p&gt;

&lt;p&gt;👆👆: double tap to activate an element for example a button.&lt;/p&gt;

&lt;p&gt;When an element is focused, Talkback will give user informations about it. For example: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;its content&lt;/li&gt;
&lt;li&gt;its value: for example for an Edit text.&lt;/li&gt;
&lt;li&gt;Its type: "Button" "Edit box", "Tab", "List: 9 of 11 items".&lt;/li&gt;
&lt;li&gt;Its state: "Selected" for a tab for example.&lt;/li&gt;
&lt;li&gt;The action you can perform with it: "activate", "toggle", etc...&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Best practices list
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Add content description to images
&lt;/h3&gt;

&lt;p&gt;Let's take for example a shopping app. In the following screen, we have an image showing a black t-shirt. If we do nothing, blind users would not know what this element is unless they perform 8 swipes to the right, to reach its label "T-shirt with cut-outs tied". So we should add a description to this image. (and all the other images on this screen)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6b341az27ow1ybrjc4z0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6b341az27ow1ybrjc4z0.png" alt="Screenshot of a sample shopping application. Showing a black tee shirt but also buttons to pick another color. Then its price and a button Add to cart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is how to do that with Jetpack Compose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;painter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;rememberCoilPainter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="n"&gt;contentDescription&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contentDescription&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The good news with Jetpack Compose is that contentDescription is mandatory!&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Hide decorative images
&lt;/h3&gt;

&lt;p&gt;When an element is purely decorative and doesn't bring any additional information to the user (for example a background, an image to illustrate a text that doesn't add any meaningful information to it), you can hide it so that Talkback will not give the focus on this element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;painter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;painterResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drawable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="n"&gt;contentDescription&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Improve element’s description
&lt;/h3&gt;

&lt;p&gt;In some situations the way that Talkback will read the element content will not be user friendly. Specifically in situations when we don't say something out-loud the same way that it's written. &lt;/p&gt;

&lt;p&gt;For example: the daily rate for a car rental: &lt;strong&gt;&lt;em&gt;$16/day&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We will never say out loud: &lt;em&gt;"Dollar sixteen slash day"&lt;/em&gt;, but if we do nothing in our app, Talkback will. That's not a very nice user experience.&lt;/p&gt;

&lt;p&gt;By overriding the text attribute of our Text composable using the Modifier.semantics property, we are able to improve the information read by Talkback.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;DailyRate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
   &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="err"&gt;“$&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;semantics&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AnnotatedString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“$&lt;/span&gt;&lt;span class="n"&gt;rate&lt;/span&gt; &lt;span class="n"&gt;dollars&lt;/span&gt; &lt;span class="n"&gt;per&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Group elements together
&lt;/h3&gt;

&lt;p&gt;In some situations, it can really improve the user experience to group element together. Imagine a screen with lots of elements on it. Imagine now that you have to go through every single element by swiping right. It's exhausting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frltx40c5ho0dzmuyw8vj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frltx40c5ho0dzmuyw8vj.png" alt="Sample of a mobile app showing the profile of a pet sitter"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example on this pet sitter profile screen. We can group together information like "no pets, home, car owner" to be focused and read all together. We can perform that by setting &lt;code&gt;mergeDescendants&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; in the &lt;code&gt;Modifier.semantics&lt;/code&gt; properties of the main row.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;Row&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;semantics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mergeDescendants&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;){}){&lt;/span&gt;
   &lt;span class="nc"&gt;Column&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nc"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;painter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;painterResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drawable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ic_pets&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
           &lt;span class="n"&gt;contentDescription&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stringResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;no_pet&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nc"&gt;Column&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nc"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;painter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;painterResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drawable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ic_car&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
           &lt;span class="n"&gt;contentDescription&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stringResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;car_owner&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/*...*/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Change reading order
&lt;/h3&gt;

&lt;p&gt;Sometimes, it makes sense to influence the reading order of the element on the screen to improve the user experience and sometimes avoid having a feature completely inaccessible because the element is unreachable.&lt;br&gt;
For example every time you design something on the z-index, let's say with a floating action button like the "Compose" button in gmail. If you do nothing, the focus to this button will be given after going through all the elements of the emails list behind (if the list is not infinite...).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcowvyejw3vi05ghk6qtw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcowvyejw3vi05ghk6qtw.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is no way to fix that with Jetpack Compose yet 😔... Here is an issue about that: &lt;a href="https://issuetracker.google.com/issues/186443263" rel="noopener noreferrer"&gt;A11y - Need a way to change manually focus order&lt;/a&gt;. Please comment or star the issue if you also think that it's important for the users.&lt;/p&gt;

&lt;p&gt;To fix that without Jetpack Compose, you can use &lt;code&gt;android:accessibilityTraversalBefore&lt;/code&gt; and &lt;code&gt;android:accessibilityTraversalAfter&lt;/code&gt; properties to specify the element before and after the &lt;code&gt;FloatingActionButton&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;com.google.android.material.floatingactionbutton.FloatingActionButton&lt;/span&gt;
   &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fabButton"&lt;/span&gt;  
   &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
   &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"wrap_content"&lt;/span&gt;
   &lt;span class="na"&gt;android:src=&lt;/span&gt;&lt;span class="s"&gt;"@drawable/ic_pencil"&lt;/span&gt;
   &lt;span class="na"&gt;android:contentDescription=&lt;/span&gt;&lt;span class="s"&gt;"@string/create_new_email"&lt;/span&gt;
   &lt;span class="na"&gt;android:layout_gravity=&lt;/span&gt;&lt;span class="s"&gt;"bottom|right"&lt;/span&gt;
   &lt;span class="na"&gt;android:accessibilityTraversalBefore=&lt;/span&gt;&lt;span class="s"&gt;"@id/mailList"&lt;/span&gt;
   &lt;span class="na"&gt;android:accessibilityTraversalAfter=&lt;/span&gt;&lt;span class="s"&gt;"@id/profilePicture"&lt;/span&gt;
   &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Facilitate navigation with headings
&lt;/h3&gt;

&lt;p&gt;On the web, screen reader users are used to navigate quickly between headings (&lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;...). It gives them a quick overview of the content and help them to be more efficient.&lt;br&gt;
Starting from Talkback 9.1, it's now also possible to do that in android apps, as long as the developer specifies it.&lt;/p&gt;

&lt;p&gt;A good example to set up headings is when you have sections in a list. Like here in this settings screen: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyjox6yu75dmu00tl42y6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyjox6yu75dmu00tl42y6.png" alt="Screenshot of the android settings to manage sound and vibration of the device. This screen has a list with different sections like Volume, Do not Disturb, Earphone"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To specify that sections of that list are headings, we have to add &lt;code&gt;heading()&lt;/code&gt; inside the &lt;code&gt;Modifier.semantics&lt;/code&gt; property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;Section&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;semantics&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;heading&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. Disable element and describe element state
&lt;/h3&gt;

&lt;p&gt;Last situation I want to illustrate is the following: you have a list of items, and a switch button on each row of the list. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn92cbo0vs0tyuet0zgfd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn92cbo0vs0tyuet0zgfd.png" alt="screenshot of an app. Setting's screen. List of setting, with on each row a text and a switch button at the end "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we do nothing Talkback will behave on each row like this: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Focus the entire row and say "Profile button"&lt;/li&gt;
&lt;li&gt;Focus on the switch button: "On - Switch - Double tap to toggle"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This can be exhausting to go through a long list of configurable rows if Talkback stops twice per row. &lt;/p&gt;

&lt;p&gt;The original composable will probably looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;checked&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;remember&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;mutableStateOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Profile details"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="nc"&gt;Switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;onCheckedChange&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A better user experience, could be something like this on each row : &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Focus the entire row and say "Profile button - ON - Double tap to toggle"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We will do that in two step : &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Disable the focus on the Switch button&lt;/li&gt;
&lt;li&gt;Add toggle behaviour to the entire row&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's go.&lt;/p&gt;

&lt;p&gt;1) Disable the focus on the Switch button&lt;/p&gt;

&lt;p&gt;We can do that by adding the &lt;code&gt;Modifier.clearAndSetSemantics&lt;/code&gt; with nothing inside. This way talkback will ignore it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;checked&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;remember&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;mutableStateOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Profile details"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="nc"&gt;Switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;onCheckedChange&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clearAndSetSemantics&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although using &lt;code&gt;clearAndSetSemantics{}&lt;/code&gt; is the usual way to ask Talkback to ignore an element, keep in mind that in general when semantics properties can be changed by setting another default parameter of a composable, that should be preferred over using the lower level semantics modifier. In this situation, we can for example set &lt;code&gt;null&lt;/code&gt; to &lt;code&gt;onCheckChange&lt;/code&gt; callback, and the switch button will be ignored by Talkback too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;checked&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;remember&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;mutableStateOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Profile details"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="nc"&gt;Switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;onCheckedChange&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2) Add toggle behaviour to the entire row&lt;/p&gt;

&lt;p&gt;We add a &lt;code&gt;toggleable&lt;/code&gt; Modifier to the row and perform in it the same action than on the switch.&lt;br&gt;
We add in the &lt;code&gt;semantics&lt;/code&gt; Modifier the &lt;code&gt;stateDescription&lt;/code&gt; properties to configure what Talkback should say regarding the switch state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;checked&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;remember&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;mutableStateOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggleable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;semantics&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="n"&gt;stateDescription&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; 
                       &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="s"&gt;"ON"&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s"&gt;"OFF"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;){&lt;/span&gt;
   &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Profile details"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="nc"&gt;Switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checked&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;onCheckedChange&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;

   &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  That's it
&lt;/h2&gt;

&lt;p&gt;That's it for my list of best practices to make your app usable for blind users.&lt;br&gt;
You can also check the Compose documentation for accessibility here : &lt;a href="https://developer.android.com/jetpack/compose/accessibility" rel="noopener noreferrer"&gt;Jetpack Compose - Accessibility Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course accessibility is not only about blind people, so I really encourage you to learn more about that. Here is where you can start : &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility" rel="noopener noreferrer"&gt;Mozilla website - what is accessibility.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this article. Don't hesitate to reach out to me on Twitter if you have any questions : &lt;a href="https://twitter.com/FannyDemey" rel="noopener noreferrer"&gt;@FannyDemey&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>a11y</category>
      <category>kotlin</category>
    </item>
    <item>
      <title>Best practice to build accessible apps with SwiftUI </title>
      <dc:creator>Fanny Demey</dc:creator>
      <pubDate>Wed, 07 Apr 2021 18:16:23 +0000</pubDate>
      <link>https://dev.to/fannydemey/best-practice-to-build-accessible-apps-with-swiftui-3cdk</link>
      <guid>https://dev.to/fannydemey/best-practice-to-build-accessible-apps-with-swiftui-3cdk</guid>
      <description>&lt;p&gt;Created: Apr 7, 2021 2:25 PM&lt;/p&gt;

&lt;p&gt;Last year I had the opportunity to learn SwiftUI development and specifically to work on making views more accessible. At that time, I set up for the team a list of best practices. Today, I've decided to share those with you.&lt;/p&gt;

&lt;h1&gt;
  
  
  How VoiceOver works
&lt;/h1&gt;

&lt;p&gt;First let's see how VoiceOver works. VoiceOver is the screen reader used on iOS by users with low vision or who are blind. Here are several gestures that you can perform anywhere on the screen, that allows you to navigate through visual elements :&lt;br&gt;
➡️  swipe to the right to go to next element&lt;/p&gt;

&lt;p&gt;⬅️  swipe to the left to go to previous element&lt;/p&gt;

&lt;p&gt;⬇️ ⬆️ swipe top to bottom or bottom to top allows you to do an action that you can configure with the rotor (see below)&lt;/p&gt;

&lt;p&gt;🔂 drawing a circle with 2 fingers will open what is called the "Rotor". It allows you to configure swipe action top &amp;lt;-&amp;gt; bottom, for example : Navigation between headers or containers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fabvqatd4ho6gxe096fr3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fabvqatd4ho6gxe096fr3.png" alt="Rotor gesture on an iPhone"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👆 single tap on an item to read an element.&lt;/p&gt;

&lt;p&gt;👆👆 double tap to activate an element for example a button.&lt;/p&gt;

&lt;p&gt;When an element is focused, VoiceOver will give user information about it. Basically VoiceOver read 4 properties for each element : &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Label : for exemple the text of the element "Today"&lt;/li&gt;
&lt;li&gt;Value : "Wednesday 8th of July" (it can give more information related to the Label. It's not mandatory, but can be useful for EditText for example).&lt;/li&gt;
&lt;li&gt;Trait :  "Button" or "Static text" or "Heading" or "Container" or "Adjustable"&lt;/li&gt;
&lt;li&gt;Hint : To give a hint to the user about the action that can be performed on this element. for example "swipe top or bottom to change the value of this element" (not mandatory also)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Those 4 properties are pronounced in this order.&lt;/p&gt;
&lt;h1&gt;
  
  
  How I test accessibility
&lt;/h1&gt;

&lt;p&gt;One good practice I applied to make my application usable for people with visual impairment was testing 2 different use cases :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use VoiceOver and validate that the user experience is good  🔊&lt;/li&gt;
&lt;li&gt;Test my application with different font size in accessibility parameters 🔎 (that can be done easily with the Accessibility Inspector. You can find it in XCode menu ⇒ Open Developer Tool ⇒ Accessibility inspector)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuqh6pa56o9t0amxn5syz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuqh6pa56o9t0amxn5syz.png" alt="Screenshot of Accessibility Inspector from Xcode"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, there are other use cases to make an app accessible, and visual impairment is not the only thing you should care about. &lt;/p&gt;
&lt;h2&gt;
  
  
  Use case 1 : using VoiceOver 🔊
&lt;/h2&gt;

&lt;p&gt;Here are some test I perform to test user experience with VoiceOver :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User can easily go from an element to another, and the order of element is logical&lt;/li&gt;
&lt;li&gt;User can identify the goal of an element thanks to a good combination of label / value / trait / hint&lt;/li&gt;
&lt;li&gt;VoiceOver does not focus on decorative elements such as image background.&lt;/li&gt;
&lt;li&gt;Some elements are grouped to facilitate comprehension and navigation (for example : an icon and its label)&lt;/li&gt;
&lt;li&gt;If using modal view, make sure that the content underneath is not accessible through VoiceOver&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Use case 2 : change the font size 🔎
&lt;/h2&gt;

&lt;p&gt;Here are some test I perform for this use case :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Texts scale when changing for a larger font in accessibility settings&lt;/li&gt;
&lt;li&gt;User can still see all the content&lt;/li&gt;
&lt;li&gt;Nothing overlaps&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  Best practice list
&lt;/h1&gt;

&lt;p&gt;When my test fails, most of the time I use a solution from the following list :&lt;/p&gt;
&lt;h2&gt;
  
  
  1/ Make the font scalable
&lt;/h2&gt;

&lt;p&gt;If you have trouble having your font scaling up with accessibility settings, you should probably take a look at this tutorial : &lt;a href="https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-dynamic-type-with-a-custom-font" rel="noopener noreferrer"&gt;https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-dynamic-type-with-a-custom-font&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  2/ Change the reading order with voiceOver
&lt;/h2&gt;

&lt;p&gt;In some situations I had to tell VoiceOver which element to focus on before another one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;HStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;buttons&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accessibility&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sortPriority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accessibility&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sortPriority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accessibilityElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, &lt;code&gt;toggle&lt;/code&gt; will have focus before buttons when the user navigate between elements with VoiceOver.&lt;/p&gt;

&lt;h2&gt;
  
  
  3/Combine elements together
&lt;/h2&gt;

&lt;p&gt;To prevent users from navigating through every single piece of elements when it's not needed, I group elements together and set a specific label for this group.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;HStack&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;....&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.....&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accessibilityElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;combine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accessibility&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Title"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0svgxw35odqtauq2zet9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0svgxw35odqtauq2zet9.png" alt="Example of a image button group with its label with VoiceOver"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4/ Change the trait type
&lt;/h2&gt;

&lt;p&gt;In some situation, I wanted had to add or remove a trait :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accessibility&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;addTraits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isHeader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accessibility&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;removeTraits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isStaticText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5/ Disable visibility of an element
&lt;/h2&gt;

&lt;p&gt;A good practice in accessibility is to hide decorative elements such as background images.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;HStack&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="c1"&gt;//... &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;background&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kt"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;I&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;home_nav_background&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accessibility&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6/ Add a more explicit label
&lt;/h2&gt;

&lt;p&gt;For example, in my app I displayed a time in this format &lt;em&gt;HH:mm&lt;/em&gt;. To make it more understandable with VoiceOver, I had to override the label of the Text (overwise VoiceOver was saying something like "HH colon mm")&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accessibility&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toSpelloutAccessibleTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;format&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"HH:mm"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7/ Adapt the design when the font becomes larger
&lt;/h2&gt;

&lt;p&gt;It can be useful t to adapt design when the font become larger. Here is how I've done it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;@SwiftUI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;(\\&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sizeCategory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;sizeCategory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ContentSizeCategory&lt;/span&gt;

&lt;span class="c1"&gt;// Then you can simply use greater than and less than comparator to change property values for example&lt;/span&gt;
&lt;span class="kt"&gt;HStack&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sizeCategory&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extraLarge&lt;/span&gt;  &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;That's it for the best practices I've tried to apply when I was developing in SwiftUI last year. The Swift API has probably evolved by now, so my best advice for SwiftUI beginner like I was (and that I actually still are as I am an android developer) is to learn from &lt;a href="https://www.hackingwithswift.com/" rel="noopener noreferrer"&gt;Hacking with swift website&lt;/a&gt;. There is a series of articles about accessibility : &lt;a href="https://www.hackingwithswift.com/books/ios-swiftui/accessibility-introduction" rel="noopener noreferrer"&gt;https://www.hackingwithswift.com/books/ios-swiftui/accessibility-introduction&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are not familiar with accessibility and the usage of VoiceOver, I also advise you to try VoiceOver on a real device. You can have a look to &lt;a href="https://youtu.be/qDm7GiKra28" rel="noopener noreferrer"&gt;this video&lt;/a&gt; to learn more about how to use VoiceOver on your iPhone&lt;/p&gt;

&lt;p&gt;I Hope my personal best practice will help you. Don't hesitate to reach out on Twitter : &lt;a href="https://twitter.com/FannyDemey" rel="noopener noreferrer"&gt;@FannyDemey&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
