Table of Contents
Designing Accessible Forms and Error Handling
Forms often require multiple inputs—such as name, email, address, or payment details—and any mistakes or omissions must be communicated clearly. If the error feedback isn’t sufficiently descriptive or can’t be detected by screen readers, users may become stuck and unable to complete essential tasks.
🎯 Why It Matters
Filling out forms can be a cumbersome process for many users, especially those who rely on screen readers or have motor impairments. Forms often require multiple inputs—such as name, email, address, or payment details—and any mistakes or omissions must be communicated clearly. If the error feedback isn't sufficiently descriptive or can't be detected by screen readers, users may become stuck and unable to complete essential tasks.
Key accessibility barriers this solution addresses:
- Focus Management: Users need to know exactly which field has an error
- Descriptive Error Messages: Feedback must be concise but meaningful—e.g., "Enter a valid email address" rather than "Invalid input"
- Visual & Verbal Indicators: Use color, icons, or text for visual cues, while also ensuring screen readers can announce the issue
💻 Implementation
Correct Code Example: Creating an Accessible Form with Error Handling in SwiftUI
Demo Description
This is a simplified form that requests an email address and password. It includes real-time validation feedback and displays an error message when necessary. The same approach can be extended to complex forms with multiple fields.
// SwiftUI
TextField("Email Address", text: $email)
.focused($focusedField, equals: .email)
.accessibilityLabel("Email Address")
.onChange(of: email) { _ in validateEmail() }
if let error = emailError {
Text(error)
.foregroundColor(.red)
.accessibilityLabel(error)
}
SecureField("Password", text: $password)
.focused($focusedField, equals: .password)
.accessibilityLabel("Password")
.onChange(of: password) { _ in validatePassword() }Code Explanation
This implementation improves accessibility by ensuring that each TextField and SecureField is explicitly labelled with clear, descriptive text such as “Email Address” and “Password,” making the form easy to understand for screen reader users. It provides immediate validation feedback by displaying text-based error messages as input changes, allowing assistive technologies like VoiceOver to announce issues as soon as they occur. The error messages themselves are concise yet meaningful—for example, “Please enter a valid email address”—so users understand exactly what needs to be corrected without being overwhelmed. In addition, the use of the @FocusState property enables optional focus management, making it possible to direct users back to the field that failed validation, while also demonstrating how focus can be tracked within the form.
Correct Code Example: Accessible Toggle (Terms and Conditions)
Demo Description
For toggles, use a full phrase in the accessibility value so VoiceOver announces both label and state on focus and when the value changes (e.g. "Accept terms and conditions on" rather than only on after the first read).
// SwiftUI – accessible toggle with full phrase announcement
Toggle(isOn: $termsAccepted) {
Text("I accept the Terms and Conditions")
}
.accessibilityLabel("")
.accessibilityValue(termsAccepted
? "Accept terms and conditions on"
: "Accept terms and conditions off")
.onChange(of: termsAccepted) { _, _ in validateTerms(moveFocus: true) }
if let error = termsError {
Text(error)
.foregroundColor(.red)
.accessibilityLabel(error)
}Code Explanation
Full phrase in value: accessibilityValue is the full “Accept terms and conditions on/off” so VoiceOver says the full phrase on focus and every time the toggle changes, not just “on”/“off”.
✅ Best Practices
Do's
- ✓Provide clear, explicit labels for all form fields
- ✓Display error messages immediately adjacent to the relevant field
- ✓Use both visual indicators (color, icons) and text for error states
- ✓Ensure error messages are announced by screen readers
- ✓Implement real-time validation with accessible feedback
- ✓Use focus management to guide users to fields with errors
- ✓Make error messages concise and actionable
Don'ts
- ✗Rely only on color to indicate errors
- ✗Use vague error messages like "Invalid input" or "Error"
- ✗Display all errors at the top of the form without field-specific feedback
- ✗Remove error messages before the user has corrected the issue
- ✗Use placeholder text as the only label for form fields
- ✗Fail to announce dynamic error messages to screen readers
🔍 Common Pitfalls
Missing Error Associations
Error messages not properly associated with their corresponding form fields, making it unclear which field has the problem
Color-Only Indicators
Using only red borders or text color to indicate errors without accompanying text or icons
Generic Error Messages
Vague messages like "Invalid" that don't explain what's wrong or how to fix it
Silent Errors
Error messages that appear visually but aren't announced by screen readers
Poor Focus Management
Not directing user attention to fields with errors, especially on form submission
Placeholder Confusion
Using placeholder text as labels, which disappears when users start typing
VoiceOver/TalkBack
Screen readers will announce field labels, current values, and error messages. When an error appears, VoiceOver should announce the error text immediately. Users navigating to a field with an error should hear both the field label and the associated error message
Switch Control
Users navigating with switch control need clear visual indicators of which field has focus and which fields contain errors. Error messages should be focusable elements in the navigation order
Dynamic Type
All form labels, input text, and error messages should scale appropriately with the user's text size preferences. Ensure layouts don't break when text size increases
Voice Control
Field labels should be clear and unique to enable voice-based form filling
🧪 Testing Steps
- 1Enable VoiceOver: Settings → Accessibility → VoiceOver
- 2Navigate through form fields: Swipe right to move between form elements
- 3Verify field labels: Ensure all fields are announced with proper labels
- 4Trigger validation errors: Enter invalid data and check error announcements
- 5Test error recovery: Correct errors and verify error messages disappear
- 6Check focus management: Ensure focus moves logically through the form
- 7Test with Dynamic Type: Increase text size and verify form remains usable
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
