This post was co-authored by Chris McMeeking and Alistair Barrell.
Accessibility Traits are yet another useful and important feature in the realm of iOS Accessibility. An Accessibility Trait allows you to choose the best description for what an element in your application does. It is important to set up these traits properly so that a user does not get confused when clicking on a "Text Field" opens the web browser.
There is a lot of misleading information out there regarding traits. Much of this comes from simplistic descriptions. Such descriptions lead developers to misuse traits, because the generic description of the trait applies to their situation. This post will take a different approach. We will describe the behavior that each trait will cause when applied to a control. Some of these traits are manifested simply by changes in VoiceOver announcement of a control, while other behaviors are less obvious. In some cases setting up an example where the trait can actually take effect is difficult! In this post we will cover:
- A couple of different categories of traits.
- Each trait, it's intended purpose, and the behavior it causes in VoiceOver
- Best Practices regarding the use of traits.
Traits that Represent ARIA Roles
An important concept in accessibility is the role an object in the UI plays. Whether an object is a static text field, button, link, or text entry field is important to share with the user. This information can often be deduced by the type of the object. For example, a UITextField should always be used for text entry. However, for some of these roles, the iOS APIs require developer input. For example, an image might behave as a button or a link, or it might just be an image. You may assume that a UIButton is a button, but what if this "button" opens a page in Safari? Traits that fall in this category should be considered mutually exclusive.
Traits that Help VoiceOver
Other traits don't directly affect the announcement of your control, but rather affect how VoiceOver interacts with your control or provide VoiceOver the context in which your control is used. This allows VoiceOver to behave more reasonably for certain types of controls. It is important to understand the effect that these traits have, as their apparent meaning can be misleading. Unlike traits that represent ARIA Roles, it is reasonable to use these traits in combination with other traits.
Enumeration of Traits
Below is a list of traits available in the iOS Framework (some omitted, as we continue to research their behaviors). Each trait is accompanied by a description of how VoiceOver behaves when it encounters an object with the given trait. We also provide a generic description or example of the objects the traits would typically be applied to. It is best to keep both the description and behaviors in mind when making the decision on whether to apply the trait or not. Traits are frequently mis-applied.
This control has no special behaviors. Applied programmatically when you want to remove all traits from the control. Using this trait in conjunction with any other trait is meaningless.
The button trait fits within the category of traits that represent ARIA roles. Objects with this trait will have the word "button" announced after their accessibility label when read out in VoiceOver.
The trait of button should be applied to controls which accept basic input events, and do not conform to one of the more specific traits. UIButtons, segments within segmented controls, and similar UI control objects will have this trait applied by default. You must specifically remove it if this trait should not apply. For example a UIButton that opens a web page in Safari should have this trait removed, and the link trait applied.
The link trait fits within the category of traits that represent ARIA roles. Objects with this trait will have the word "link" announced after their accessibility label when read out in VoiceOver. Links open a URL in an external browser. This the important distinction between buttons. Only apply the trait of link when the users interaction with the control will take them out of your application and into Safari.
Search Field (UIAccessibilityTraitSearchField)
Objects with this trait announce as "Search Field". A lot of iOS Applications (App Store, iTunes, etc.) use a simple search field to allow users to easily find elements within the application. This being a common idiom in iOS it makes sense to have a trait designated for this purpose. Note, that this is specifically for searches within the context of the application. The text field on Google.com for example, would not have this trait applied.
The image trait fits within the category of traits that represent ARIA roles. Objects with this trait will have the word "image" announced after their accessibility label when read out in VoiceOver. Unlike other traits in the ARIA roles category, you may reasonably combine this trait with other ARIA roles. Having a button that is also an image is perfectly reasonable.
This trait should be applied when the visual appearance of an object presents important information. For example, if you have an image that is just a custom button, and its appearance doesn't present new information, it probably isn't really an image. It is in fact just a button. However, if you have a button, and this button has some custom appearance that provides information about the button, or the button has a background image, a button may be an image.
Objects that are Selected read out as "selected". This should be considered the state of a control. Unlike web technologies, in which groups of controls behave as selected/unselected pairs, this control simply exists to mark specific elements selected.
A common use for this trait would be the active tab on a tab bar.
Summary Element (UIAccessibilityTraitSummaryElement)
Marking an element as a Summary Element causes an interesting behavior. When the app first loads, the summary element is read off, including traits and hints. However, it does not receive focus. Also note that Summary Elements only get read out on loading of your app. So if you're navigating a multi page app, your summary elements will not get read out repeatedly.
Use this trait on elements of your front page that merit drawing attention to, but are not early on in your apps focus order. You don't want users to hear your summary element, flick to the right, and have to hear it right away again! Finally, you may only have one summary element in a view.
User Interaction Enabled (UIAccessibilityTraitNotEnabled)
Controls with this trait read off as "dimmed" when their traits get read off. The typical use for this would be when you want to disable a button temporarily. It is still part of your UI, and VoiceOver users need to know it's there, but it cannot currently be activated.
ATTENTION: The interface builder displays this trait as "User Interaction Enabled" while the programmatic method of applying traits has the trait named UIAccessibilityTraitNotEnabled. So, disabling the trait in Interface Builder is the same as applying the trait in code. As such, in interface builder, you almost always want to see this box checked under your traits for a given item. Unchecking this box will cause your elements to be read out as "dimmed"!
Best Practice: This trait can be accompanied by most other traits. However, Static Text and Dimmed probably do not make sense. You cannot disable interaction with text. If you truly wish to do so, what you probably mean to do is to mark an element as NOT an accessibility element.
Frequent Updates (UIAccessibilityTraitUpdatesFrequently)
This trait helps VoiceOver better handle controls with dynamic content. In such cases VoiceOver will poll the control while it is focused, rather than attempting to share all text that has ever existed in the control.
Let's consider a digital stopwatch, with an hour, minute and second. A reasonable accessibility label for this might read out
VoiceOver: One hour, two minutes, and fifty five seconds.
This is perfect! However, as it is reading this out, the control has updated to count up several seconds. So now it displays 1:02:58. Let's consider two scenarios. First, that the Updates Frequently trait has not been set. After the above announcement we would have the following.
VoiceOver: One hour, two minutes, and fifty six seconds
Notice that VoiceOver picked up on the update! Even though it is now in the 58th second, VoiceOver has fallen behind, and is reading the announcement for 1:02:56. This problem will get worse and worse, the longer the user stays on the updating field, with VoiceOver announcing every update that has happened!
Now, let's assume that the Updates Frequently trait has been set properly. After our first announcement, for 1:02:55, we would have
VoiceOver: One hour, two minutes, and fifty eight seconds
This behavior is obviously more desirable! Notice, if the control does not have accessibility focus, VoiceOver will not inform the user of the updates. Other considerations, like dynamic notifications, should be used for circumstances in which you'd like the user to be notified of content changes, without specifically having the content focused.
Starts Media Session (UIAccessibilityTraitStartsMediaSession)
When a VoiceOver user double taps the screen on a button, the button is clicked, and the label of the button repeated to the user. This would obviously be frustrating if the purpose of the button were to play a sound! Especially a short sound. Interrupting the first few seconds of Yellow Submarine isn't the end of the world, but what if a user is checking out new alert sounds? The sound may be shorter than the announcement! This would be highly frustrating. Applying this trait to a button stops this behavior, canceling any announcement, allowing sounds played as a result of interaction with the control to be heard.
Adjustable controls will announce as "Adjustable" as well as having a longer announcement appended to the hint:
This is your hint, swipe up or down to adjust the value.
Use of this trait has a few interesting consequences. First, any control with this applied needs to understand how to adjust itself, and ensure it does so in response to the swipe up/swipe down gestures. This also means that it breaks the typical swipe up/swipe down VoiceOver gestures. So things like heading navigation (or others, based on the rotor setting) will not work on elements that have this applied. Overuse of this trait should be avoided!
Best Practice: Only use this on UISlider elements.
Direct Interaction (UIAccessibilityTraitAllowsDirectInteraction)
This trait is particularly interesting. Objects with this trait will have VoiceOver pass through touch events, so that the control can handle them directly. It is unlikely that you should use this in an accessibility context, but rather, used when VoiceOver interacting with a control on behalf of the user just does not make sense. For example, a drawing application. If you were to implement Paint in iOS, would it make sense to have VoiceOver interact with the Paint window? Of course not.
Header elements add two behaviors to controls. The obvious behavior is that they read off as "header". Additionally, if the rotor is set to "Headings" a flick up or down on the screen will navigate directly to headings in order. Adding headings to your application makes navigation easy.
Best Practice: Add at least one heading per view! For applications with large sections of content on one screen add additional headings, as necessary and sensible, to help users navigate.
While the impact of traits may seem somewhat subtle and insignificant, it is highly important for VoiceOver users. Traits let the Accessibility API know specific information about your elements that can help VoiceOver and other aspects of the API handle your elements in a clearer and more uniform way. Consistent announcement of UI controls, particularly those related to ARIA Roles, helps provide context to non-sighted users. If not used consistently and correctly, traits within your app can cause undue confusion, negating any positive affects, or even making things worse.
In the descriptions of each traits we mentioned some combinations of traits that don't make sense together. There are many more pairings of traits that can cause problems that were not outlined here. The best way to avoid these contradictions and confusing situations is just to think carefully about pairing two Accessibility Traits with each other. Does your pairing really make sense? Is there a way you could simplify it by omitting one of your traits while still staying true to the function of your element?
- Make sure that the traits you assign to elements accurately reflect what that element is/does!
- If the content on the page is dynamic, make sure that your traits change when the function of an element changes.
- Consider not only the description of the trait, but also the behavior that the trait will cause. Does it make sense within the context of your application? Traits do nothing more than help VoiceOver, they DO NOT cause any other behaviors. So if a given announcement within VoiceOver does not make sense for your use case, perhaps the trait should be removed. Even if it meets the generic criteria set forth by the Apple API summary of the trait.
- Read more Deque University Best Practice posts.
- Sign up for a mobile accessibility webinar.
- Discover how Deque products can help you make sure your apps and websites fully accessible.