Table of Contents
Implementing Accessibility Properties in iOS
In iOS, accessibility properties are the key to creating user interfaces that everyone can use. This lesson will show you, step by step, how to set up accessibility labels, hints, traits, and values using SwiftUI code. By following these steps, you will ensure that assistive technologies like VoiceOver can accurately describe and understand the elements on your screen.
🎯 Why It Matters
Consider a user trying to fill out a form using VoiceOver. Without proper accessibility labels, they might hear "text field" with no indication of what information to enter. Without hints, they won't know the expected format for dates or other structured data. Without traits, screen readers can't convey whether an element is a button, link, or header.
iOS provides four main accessibility properties:
- accessibilityLabel: A concise, descriptive text (e.g., "Play Video" or "Login Field") that identifies the element
- accessibilityHint: Additional context about the element's purpose or action (e.g., "Starts video playback")
- accessibilityTraits: Defines the element's role (e.g.,
.button,.link,.header) so screen readers can announce it appropriately - accessibilityValue: Represents dynamic information associated with the element, like the current position of a slider
These properties work together to create a complete, understandable experience for assistive technology users.
💻 Implementation
Correct Code Example: Setting Accessibility Label, Hint, and Traits for a Date Input
Demo Description
Here's a code snippet demonstrating how to set Accessibility Label, Hint, and Traits for a TextField used for date of birth entry in SwiftUI:
// SwiftUI
import SwiftUI
struct ContentView: View {
@State private var dateOfBirthInput: String = ""
var body: some View {
VStack {
Text("Date of Birth")
.accessibilityAddTraits(.isHeader) // Header trait announces "heading"
TextField("DD/MM/YYYY", text: $dateOfBirthInput) // Visually hints at the format
.textFieldStyle(RoundedBorderTextFieldStyle()) // Common styling for text fields
.keyboardType(.numbersAndPunctuation) // Improves usability for date entry
.accessibilityLabel("Date of Birth") // Clear audible label for VoiceOver
.accessibilityHint("Enter your date of birth using DD/MM/YYYY format. For example, 28/05/1990.") // Crucial format guidance
.accessibilityAddTraits(.isKeyboardKey) // For custom text fields
}
}
}Code Explanation
In this snippet, the SwiftUI TextField for date of birth uses .accessibilityLabel for a clear VoiceOver label and .accessibilityHint to explain the "DD/MM/YYYY" format with an example. Finally, the .accessibilityAddTraits(.isKeyboardKey) modifier is applied to inform assistive technologies when a custom text field functions as a keyboard input, which can refine the user interaction. This ensures accessibility by clearly labeling the field and guiding the user on the expected input format.
✅ Best Practices
Do's
- ✓Use clear, concise accessibility labels that describe the element's purpose
- ✓Provide accessibility hints that explain what will happen when the element is activated
- ✓Apply appropriate traits (`.button`, `.header`, `.link`) to help screen readers announce element types correctly
- ✓Update accessibility values for dynamic content (sliders, progress bars, toggles)
- ✓Keep labels and hints brief—VoiceOver users prefer concise information
- ✓Test all accessibility properties with VoiceOver enabled
- ✓Use contextually relevant descriptions that match the element's current function
Don'ts
- ✗Repeat visible text in accessibility labels when it's already clear
- ✗Include element types in labels (e.g., "Submit Button")—traits handle this
- ✗Write overly long hints that overwhelm users
- ✗Forget to update accessibility properties when UI state changes
- ✗Use technical jargon or unclear descriptions in labels or hints
- ✗Leave interactive elements without accessibility labels
- ✗Add redundant information that doesn't provide additional value
🔍 Common Pitfalls
Missing Labels
Interactive elements without accessibility labels are announced generically (e.g., "button") with no indication of their purpose
Redundant Information
Including the element type in the label (e.g., "Submit Button" when the `.button` trait already announces "button")
Overly Long Hints
Writing paragraph-length hints that take too long to read and frustrate users
Static Values
Forgetting to update `.accessibilityValue()` for dynamic elements like sliders, progress bars, or toggles
Unclear Format Instructions
Not providing examples in hints for fields with specific format requirements (dates, phone numbers, credit cards)
Incorrect Traits
Applying wrong or multiple conflicting traits that confuse screen reader announcements
No Context for Icons
Icon-only buttons without descriptive labels that explain their function
VoiceOver/TalkBack
Screen readers announce elements by combining the accessibility label, traits, value, and hint. For example, a button might be announced as "Submit. Button. Submits the form." The label is announced first, followed by the trait, then the hint. For sliders and other adjustable elements, the current value is announced as the user interacts with them. VoiceOver users can swipe up or down on adjustable elements to change values incrementally
VoiceOver Rotor
Users can navigate by element type using the rotor. Elements with the `.isHeader` trait appear in the "Headings" navigation mode, allowing users to quickly jump between sections
Voice Control
Clear accessibility labels enable voice control users to say "Tap [Label Name]" to activate elements
Switch Control
Proper labeling helps switch control users understand what each element does before activating it
Braille Displays
Accessibility labels, hints, and values are converted to braille, allowing users with deafblindness to understand interface elements
🧪 Testing Steps
- 1Enable VoiceOver: Settings → Accessibility → VoiceOver
- 2Navigate to labeled elements: Swipe through your interface
- 3Verify labels: Ensure each element has a clear, descriptive label
- 4Check hints: Confirm hints provide useful context without being redundant
- 5Test traits: Verify elements are announced with correct types (button, header, link)
- 6Test dynamic values: Adjust sliders, toggles, and other controls to verify values update
- 7Check format guidance: For text fields with specific formats, verify hints explain the expected format
- 8Test state changes: Ensure accessibility properties update when element state changes
- 9Verify header hierarchy: Navigate by headers using the VoiceOver rotor to test `.isHeader` trait
Become a member to read this solution, and all of Ma11y.
This resource is part of our member knowledge base. Log in or create an account to unlock:
- Complete accessibility guidance and implementation examples
- Curated compliance frameworks and checklists
- Early access to new tools and features
