-
Notifications
You must be signed in to change notification settings - Fork 29.8k
Description
Use case
Description
Form validation error messages in Flutter Web are not semantically linked to their corresponding input fields via aria-describedby, which is required for WCAG 2.2 compliance (Success Criteria 3.3.1 and 3.3.3).
Current Behavior
When a TextFormField displays a validation error:
- ✅ The input element correctly has
aria-invalid="true" - ❌ The input element is missing
aria-describedbylinking to the error message - ❌ Screen readers announce "invalid" but don't read the error message with the input
Current DOM structure:
Expected Behavior
The input should be semantically linked to its error message:
Email is required **Expected screen reader experience:** - Focus on Email field → "Email, text field, invalid. Email is required" - Error is announced together with the input context - User immediately understands what needs to be correctedLive Demo
Before (current behavior): https://flutter-demo-04-before.web.app
Steps to Reproduce
- Visit the demo URL
- Click "Submit" to trigger validation errors
- Open browser DevTools (F12)
- Inspect the email or password
<input>element - Notice:
aria-invalid="true"is present, butaria-describedbyis missing
WCAG 2.2 Requirements
This issue affects compliance with:
- SC 3.3.1 Error Identification (Level A): Error messages must be programmatically associated with the relevant form control
- SC 3.3.3 Error Suggestion (Level AA): When an input error is detected, suggestions for correction should be provided and linked to the control
Reference: WCAG 2.2 Understanding Error Identification
Proposal
Proposed Solution
This would require coordinated changes across the framework and engine:
1. Framework: Add describedBy Property to Semantics
File: packages/flutter/lib/src/semantics/semantics.dart
Add a new property to SemanticsProperties:
/// A set of [SemanticsNode.identifier]s that describe this node.
///
/// On web, this translates to aria-describedby pointing to the
/// DOM elements of the referenced semantics nodes.
///
/// This is used to semantically link form controls to their
/// error messages, help text, or other descriptive content.
final Set? describedBy;### 2. Framework: Link Inputs to Error Messages
File: packages/flutter/lib/src/material/input_decorator.dart
Modify _HelperError._buildError() to assign an identifier:
Widget _buildError() {
return Semantics(
container: true,
identifier: 'input-error-${widget.hashCode}', // Assign stable ID
liveRegion: !MediaQuery.supportsAnnounceOf(context),
child: /* error widget */,
);
}And update the input field's semantics to reference it:
Semantics(
textField: true,
describedBy: hasError
? {'input-error-${hashCode}'} // Link to error
: null,
child: /* input widget */,
)### 3. Engine: Pass describedBy Through Update Pipeline
File: lib/ui/semantics.dart
Add parameter to SemanticsUpdateBuilder.updateNode():
void updateNode({
// ... existing parameters ...
List? describedBy,
});### 4. Engine Web: Render aria-describedby
File: lib/web_ui/lib/src/engine/semantics/semantics.dart
Store and track the describedBy references, then render the attribute:
void _updateDescribedBy() {
if (describedByNodes.isNotEmpty) {
// Resolve semantics node IDs to DOM element IDs
final ids = describedByNodes
.map((nodeId) => owner.getNodeById(nodeId)?.element.id)
.whereType()
.join(' ');
element.setAttribute('aria-describedby', ids);
} else {
element.removeAttribute('aria-describedby');
}
}## Related Issues/PRs
- Mentioned in PR Split hint from label and expose it via aria-description or aria-describedby #169157 (which addresses
hint→aria-description, a separate concern) - Related to issue Flutter Web: aria-describedby must be an available property on all component types (Accessibility) #162140
Impact
- Severity: High - affects accessibility compliance for all Flutter Web forms
- Users affected: Screen reader users, keyboard-only users, users with cognitive disabilities
- Platforms: Web only (native platforms handle this differently)
Additional Context
This is distinct from PR #169157, which correctly implements aria-description for the hint property. The hint property is for supplementary instructional text, while errorText is for validation feedback that must be linked to the control.
| Use Case | Property | ARIA Pattern |
|---|---|---|
| Hint text | SemanticsProperties.hint |
aria-description (inline string) |
| Validation errors | InputDecoration.errorText |
aria-describedby (element ID reference) |
Both patterns are valid but serve different purposes per ARIA specifications.