conflicting-traits
Mobile validation
On iOS, accessibility traits tell VoiceOver and Switch Control what an element is and how it behaves, for example .button, .link, or .header. When an element has traits that contradict each other, assistive technologies may announce two incompatible roles, expose the wrong action, or ignore a gesture.
Choose the one trait that best matches the element's behavior, or split the element into separate components, so each has a single, clear role.
Note: This validation applies to iOS only. Accessibility traits are an iOS concept, and Android elements expose a single role, so there are no Android or cross-platform examples.
These trait combinations conflict with each other:
| When | Is combined with | The user |
|---|---|---|
.adjustable | .causesPageTurn | encounters conflicting event handlers |
.adjustable | .header | cannot navigate to this heading with the rotor |
.allowsDirectInteraction | .button | cannot activate the component |
.allowsDirectInteraction | .keyboardKey | cannot activate using the keyboard key |
.allowsDirectInteraction | .link | cannot activate the link |
.allowsDirectInteraction | .searchField | cannot activate the search field |
.allowsDirectInteraction | .toggleButton | cannot activate the toggle button |
.button | .link | cannot tell whether activation will leave the app |
.button | .searchField | cannot tell what will happen on activation |
.link | .searchField | cannot tell what will happen on activation |
Pass Patterns
iOS
The tappable label has a single trait, .button, that matches its behavior.
let submitLabel = UILabel()
submitLabel.text = "Submit"
submitLabel.isUserInteractionEnabled = true
submitLabel.accessibilityTraits = .button
submitLabel.addGestureRecognizer(
UITapGestureRecognizer(target: self, action: #selector(handleTap))
)The tappable text has a single trait, .isButton, that matches its behavior.
Text("Submit")
.onTapGesture { submit() }
.accessibilityAddTraits(.isButton)Fail Patterns
iOS
The label has both the .button and .link traits, so users cannot tell whether activating it will leave the app.
let submitLabel = UILabel()
submitLabel.text = "Submit"
submitLabel.isUserInteractionEnabled = true
submitLabel.accessibilityTraits = [.button, .link]
submitLabel.addGestureRecognizer(
UITapGestureRecognizer(target: self, action: #selector(handleTap))
)The text has both the .isButton and .isLink traits, so users cannot tell whether activating it will leave the app.
Text("Submit")
.onTapGesture { submit() }
.accessibilityAddTraits([.isButton, .isLink])Try It Yourself
Using a screen reader
New to screen reader testing, or need a refresher?
Review this article first: Practical guides for using screen readers
- Turn on VoiceOver.
- Swipe right or left to move to the element.
- Listen to the roles announced after its name, and try to activate it with a double tap.
Expected results: VoiceOver announces a single role that matches the element's behavior, and the element responds as expected.
Actual results: VoiceOver announces more than one role, such as both “button” and “link”, or the element does not respond to the expected gesture.
Using developer tools
- In Xcode, open Xcode > Open Developer Tool > Accessibility Inspector, select the simulator or device, and point at the element.
- Check the element's Traits.
Expected results: The Traits contain no conflicting combination from the table above.
Actual results: The Traits contain a conflicting combination, such as Button and Link.
FAQ
Why is this issue marked as Critical?
Conflicting traits can make VoiceOver and Switch Control announce the wrong role, ignore gestures, or block activation altogether. Users may be unable to complete a task, or may be sent somewhere they did not expect, so it is rated critical.
How does this issue relate to 4.1.2 Name, role, value?
SC 4.1.2 requires the role of every user interface component to be programmatically determinable. When an element exposes traits that contradict each other, assistive technologies cannot determine a single, consistent role, and may not be able to operate the element reliably.
How does this issue relate to 1.3.1 Info and Relationships?
Conflicting traits relate to 1.3.1 because information and relationships must be programmatically determinable and accurate. When one element exposes multiple, incompatible traits, assistive technology cannot determine a single role or relationship.
This can cause VoiceOver or Switch Control to announce different roles, expose the wrong action, or ignore a gesture. That breaks the programmatic mapping between what is presented and how it is structured.
To meet 1.3.1, assign one trait that matches the element’s behavior, or split it into separate components so each has a single, clear role.
Standards and Regulations
| Standard | Success Criterion | Reference |
|---|---|---|
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) | For all user interface components, the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to assistive technologies. |
| WCAG 2.2 | 1.3.1 Info and Relationships (A) | Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text. |
| EN 301 549 | 11.4.1.2 Name, Role, Value | Same as the WCAG text. |
| EN 301 549 | 11.1.3.1 Info and Relationships | Same as the WCAG text. |