<?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>Forem: Harris Borawski</title>
    <description>The latest articles on Forem by Harris Borawski (@hborawski).</description>
    <link>https://forem.com/hborawski</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%2F1288230%2Fb51c6f51-1a2e-4411-99a8-0890973dd4ef.png</url>
      <title>Forem: Harris Borawski</title>
      <link>https://forem.com/hborawski</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/hborawski"/>
    <language>en</language>
    <item>
      <title>Making Accessible Links in SwiftUI</title>
      <dc:creator>Harris Borawski</dc:creator>
      <pubDate>Wed, 18 Dec 2024 21:41:02 +0000</pubDate>
      <link>https://forem.com/intuitdev/making-accessible-links-in-swiftui-3l5g</link>
      <guid>https://forem.com/intuitdev/making-accessible-links-in-swiftui-3l5g</guid>
      <description>&lt;p&gt;SwiftUI has streamlined Apple platform UI development, but it's not without its flaws, especially regarding accessibility. A notable concern is the inaccessibility of links within the &lt;code&gt;Text&lt;/code&gt; view—screen readers fail to recognize these inline links as actionable elements. In this post, we'll dissect this issue, exploring its impact on user experience and providing guidelines on how developers can enhance accessibility (&lt;a href="https://www.a11yproject.com/" rel="noopener noreferrer"&gt;a11y&lt;/a&gt;) in their SwiftUI applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Let's start with some simple code to illustrate the problem. Here is a simple link within text, rendered using Markdown.&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="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://developer.apple.com/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&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;"Please review our [Terms and Conditions](&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;absoluteString&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;)"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2F4hfr4g3k4rc6ijtuhptu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F4hfr4g3k4rc6ijtuhptu.png" alt="A screenshot from a iPhone simulator that shows a line of text saying 'Please review our Terms and Conditions'. 'Terms and Conditions' is styled as a link in a different color." width="656" height="70"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can imagine, inlining links with text is a common use case across apps. They're used for user agreements, deep-linking other pages, and simply linking to external articles.&lt;/p&gt;

&lt;p&gt;However, when links are added like this, it is not clear to screen-readers that they are tappable. Using the Accessibility Inspector, we can see this issue in action for the code above:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fcbr3067ooeqxzugjv5vt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fcbr3067ooeqxzugjv5vt.png" alt="The inspected element is 'Please review our Terms and Conditions, text'. It is of type 'text'." width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"Please review our Terms and Conditions" is one label (good) with type 'text' (not good). The screen-reader will not announce this as interactive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Solution 1: Add a Button Trait
&lt;/h3&gt;

&lt;p&gt;Adding a button trait to the &lt;code&gt;Text&lt;/code&gt; element will ensure the screen-reader knows the element is interactive. Here’s how you could implement 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="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://developer.apple.com/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&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;"Please review our [Terms and Conditions](&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;absoluteString&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&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;accessibilityAddTraits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isButton&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, when a text segment contains multiple links, differentiating between them becomes a challenge. The entire text block is treated as a single UI element, which isn't ideal when you want users to choose between multiple links. This solution can make the text look like a button to screen-readers, but it doesn't provide the granularity needed for multiple links within the same text.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solution 2: Redesign the User Interface
&lt;/h3&gt;

&lt;p&gt;A more robust but labor-intensive solution is to redesign the user interface so that links do not have to be appended with additional text. By isolating links from other text, you can define each link as a SwiftUI &lt;code&gt;Link&lt;/code&gt;, which is inherently more accessible. (A &lt;code&gt;Link&lt;/code&gt; will be presented to screen-readers as a &lt;code&gt;button&lt;/code&gt;.)&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;Link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Terms and Conditions"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://developer.apple.com/"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach maintains the visual and functional distinction of each link, improving accessibility by making each link individually selectable and actionable.&lt;/p&gt;

&lt;p&gt;However, redesigning the user interface may not always be feasible. It can involve significant changes to the app's design and layout, which may affect the project timeline, resources, or even the overall user experience.&lt;/p&gt;

&lt;p&gt;(For products that expect public usage, ensuring accessibility should be a priority from the outset of the design process, as retrofitting solutions often leads to compromises in user experience and functionality.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Both solutions offer ways to make inline links more accessible in SwiftUI, though each comes with its own set of trade-offs. The choice between adding a button trait to the entire text block and redesigning the UI to isolate links should be made based on the specific needs of the project, the frequency and nature of the links in question, and the available resources. Of course, there are probably many other solutions as well, and I hope this article helps you on the path to exploring them!&lt;/p&gt;




&lt;h2&gt;
  
  
  About the Author
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/KVSRoyal" rel="noopener noreferrer"&gt;Koriann&lt;/a&gt; (like the "corian" in "coriander") South is an accomplished iOS developer with a passion for crafting seamless and accessible user interfaces. Since joining Intuit in 2022, she has played a pivotal role in the development of the company's design system, ensuring that it meets the highest standards of accessibility and usability. With a keen eye for detail and a commitment to inclusivity, Koriann's work helps ensure that Intuit's products are accessible to millions of users worldwide. In her spare time, Koriann enjoys exploring the latest advancements in technology and sharing her knowledge with the developer community.&lt;/p&gt;




&lt;h4&gt;
  
  
  AI Acknowledgement
&lt;/h4&gt;

&lt;p&gt;This was written with the help of ChatGPT. I wrote the draft, then I used ChatGPT to rephrase my sentences, and then I rewrote the rephrasing I was unsatisified with and added a few more sentences for flavour.&lt;/p&gt;

</description>
      <category>swiftui</category>
      <category>ios</category>
      <category>a11y</category>
    </item>
  </channel>
</rss>
