Accessibility in iOS 14 Widgets With SwiftUI

Create empowering widgets for your users

Rudrank Riyam
Oct 23 · 6 min read
Image of an iPhone consisting of Music, Photos and Batteries widgets.
Image of an iPhone consisting of Music, Photos and Batteries widgets.
Photo by Omid Armin on Unsplash

Introduction

This article covers the foundational adaptation of creating a good VoiceOver, Voice Control, and adaptive display experience with your widgets using SwiftUI.

Accessibility in SwiftUI

.accessibilityLabel(“Settings“)

Developers can take advantage of the straightforward APIs and implement these in their apps.

And also widgets.

So let’s look at some of the topics of accessibility and how you can implement them in your widgets!

VoiceOver and Widgets

I’ll focus on some general accessibility APIs that you can adapt to your apps for a great experience for VoiceOver users.

  • accessibilityLabel(_:) You’ll usually use this method for providing labels to images and logos. You may have the logo of your app on the widget, which you may want the user to hear, and not logo_image or something along that line.
Image("logo_image").accessibilityLabel(model.appName)
  • accessibilityValue(_:) If your widget has dynamic value wtih a static label, you should use this method. For example, in a book-reading tracker widget, the number of books read, which will be dynamic, can be defined using this method.
Text("Number of books read")
.accessibilityValue("\(model.booksRead)")
  • accessibilityHint(_:) The hint is used for communicating to the user what happens after they perform an action on the accessibility elements. This helps provide information that cannot be accommodated in the main accessibilityLabel itself. For example, on a stack of widgets, the hint provided by the system is — “Swipe up or down to select a custom action, then double-tap to activate.” When you swipe up or down on an element in a widget that is in the stack, the custom actions will be “Next Widget” and “Previous Widget.” Although, a widget is either static data or deep links that would tell the user that it is a button. I haven’t come across a widget created by Apple where custom hints are provided, as it is something not needed in this case.
  • accessibilityAction(_:_:) An action on a widget is either nothing for glanceable data, or it directly opens the app through the deep link on the click of an element. So a custom action may not be needed.
  • accessibilityElement(children:) This instance method is particularly useful when you may want to combine a lot of text to be read at once. For example, the Podcasts app combines the name of the podcast, author, data, and the description into one element.
VStack {
Text("\(model.date)")
Text(model.author)
Text(model.title)
Text(model.description)
}
.accessibilityElement(children: .combine)
  • accessibilityHidden(_:) There may be cases when you want to hide the image completely from VoiceOver to read the element. In this case, you should use this method. For example, in the Weather widget, the icon for describing the weather is not read out by the reader. Do note that Image also has an initialiser, where the readers skip reading the image element.
Image(decorative: model.imageName)
  • accessibilityAddTraits(_:) For best describing the accessibility element and its characteristics, this method is used. For example, you may have title text in your app, and for distinguishing it from other texts, you can use the isHeader type property for it.
VStack {
Text("Gradient Game").accessibilityAddTraits(.isHeader)
ForEach(model.histories, id: \.self, content: HistoryView.init)
}

Apart from that, to configure the widget using intents, the user may use a long double-press to edit the widget and open the configuration menu. In my general observation, the list in the menu has access to accessibility benefits natively.

For example, when providing a title in INObjectSection, it automatically configures it with the header trait.

INObjectSection(title: "Categories", items: categories)

With this topic coming to an end, I hope you create a wonderful experience for VoiceOver users!

Voice Control and Widgets

If your widget is VoiceOver accessible, it is usually Voice Control accessible as well. The part that can be improved is adding alternate names to labels, which can get long and repetitive in a systemMedium or systemLarge widget.

The input labels method accessibilityInputLabels(_:) gives an alternate label while using Voice Control and Full Keyboard Access.

I’ve spent around two hours trying on the latest versions of Xcode to get this working, but unfortunately, it doesn’t work with widgets yet, though it works perfectly fine on the app. This is a bug, and I’ve filed feedback regarding the same.

When this works in the future, the code may seem similar to this where VoiceOver reads all the elements as one, whereas Voice Control only shows the title, to reduce clutter on the screen while making it easier for the user to say the title for Voice Control to process that command.

VStack {
Text("\(model.date)")
Text(model.author)
Text(model.title)
Text(model.description)
}
.accessibilityElement(children: .combine)
.accessibilityInputLabels([model.title])

Display/Text Sizes and Widgets

Another great thing about SwiftUI is that this feature is supported out of the box. If you’re using the normal Font and not hardcoding the sizes, SwiftUI will automatically scale the text sizes according to the system preference. And this applies to widgets as well.

.font(.caption2)

The best way to support this feature is to test it. If you find your design getting out of the widget even in non-accessibility category sizes, you may need to rethink your designs in an accessibility-oriented way because widgets are supported on the iPod Touch (4" display) and SE(4.7" display) as well, and it should look good on all the devices.

Supporting accessibility text sizes

But I understand. Widgets are small, and you may find it difficult to support the accessibility category sizes. Or even xxxLarge/xxLarge sizes. In that case, you can try to handle these cases with a different design altogether.

Supporting large text sizes

Apart from scalable fonts, if you go to Settings > Display & Text Size, you’ll find several preferences for the users to set like Reduce Transparency, Increase Contrast, Differentiate Without Color, etc.

To respect the user’s preferences, SwiftUI gives us powerful environment values that you can read from and add conditions in your widgets accordingly.

I’ll briefly list one and how to use it.

  • legibilityWeight This reflects the value of the Bold Text display setting. By default, the view adapts to it automatically. But if you have specified a font weight, you can add the condition to respect the value of legibilityWeight.
Supporting bold texts

The whole list can be found in the EnvironmentValues documentation, which lists the major ones that you can adapt in your widgets. Most of them can be configured in that way by providing a conditional view or modifier, like in the case of sizeCategory and legibilityWeight.

  • accessibilityDifferentiateWithoutColor Use a different design with shapes and symbols to convey meaning instead of just relying on color when this condition is true.
  • accessibilityReduceTransparency With this condition true, the background should not be transparent or blurred but opaque instead. A great example is the Batteries widget, which has a translucent background but becomes opaque when this boolean is set to true.
  • colorSchemeContrast You can adapt your UI to handle the ColorSchemeContrast increased case by increasing the contrast ratio by providing alternate high contrast images and colors.

There’s a great WWDC 2020 session on making your app visually accessible that I recommend you watch. One particular line that stood out for me by Drew Haas was the following:

“Early stages of development are the best time to start thinking about visual accessibility accommodations, but it’s really never too late to dig in.”

Conclusion

And making them accessible for everyone is the cherry on the cake. You may have already started working on your widgets, or already shipped some great ones by now. But if you haven’t, it’s a great time to think and design from an accessibility perspective!

I hope you gained some value from this article and will implement it in your widgets.

Better Programming

Advice for programmers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store