Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit df6de88

Browse files
authored
Add support for assertive announcements in aria-live (#34640)
1 parent 6b05187 commit df6de88

File tree

2 files changed

+50
-4
lines changed

2 files changed

+50
-4
lines changed

lib/web_ui/lib/src/engine/semantics/accessibility.dart

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,21 @@
55
import 'dart:async';
66
import 'dart:typed_data';
77

8-
import '../../engine.dart' show registerHotRestartListener;
8+
import '../../engine.dart' show registerHotRestartListener;
99
import '../dom.dart';
1010
import '../services.dart';
1111
import '../util.dart';
1212

13+
/// Determines the assertiveness level of the accessibility announcement.
14+
///
15+
/// It is used to set the priority with which assistive technology should treat announcements.
16+
///
17+
/// The order of this enum must match the order of the values in semantics_event.dart in framework.
18+
enum Assertiveness {
19+
polite,
20+
assertive,
21+
}
22+
1323
/// Singleton for accessing accessibility announcements from the platform.
1424
final AccessibilityAnnouncements accessibilityAnnouncements =
1525
AccessibilityAnnouncements.instance;
@@ -63,15 +73,19 @@ class AccessibilityAnnouncements {
6373
final Map<dynamic, dynamic> dataMap = inputMap.readDynamicJson('data');
6474
final String? message = dataMap.tryString('message');
6575
if (message != null && message.isNotEmpty) {
66-
_initLiveRegion(message);
76+
/// The default value for politeness is `polite`.
77+
final int ariaLivePolitenessIndex = dataMap.tryInt('assertiveness') ?? 0;
78+
final Assertiveness ariaLivePoliteness = Assertiveness.values[ariaLivePolitenessIndex];
79+
_initLiveRegion(message, ariaLivePoliteness);
6780
_removeElementTimer = Timer(durationA11yMessageIsOnDom, () {
6881
_element!.remove();
6982
});
7083
}
7184
}
7285

73-
void _initLiveRegion(String message) {
74-
_domElement.setAttribute('aria-live', 'polite');
86+
void _initLiveRegion(String message, Assertiveness ariaLivePoliteness) {
87+
final String assertiveLevel = (ariaLivePoliteness == Assertiveness.assertive) ? 'assertive' : 'polite';
88+
_domElement.setAttribute('aria-live', assertiveLevel);
7589
_domElement.text = message;
7690
domDocument.body!.append(_domElement);
7791
}

lib/web_ui/test/engine/semantics/accessibility_test.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,37 @@ void testMain() {
5555
() =>
5656
expect(domDocument.getElementById('accessibility-element'), isNull));
5757
});
58+
59+
test('Default value of aria-live is polite when assertiveness is not specified', () {
60+
const Map<dynamic, dynamic> testInput = <dynamic, dynamic>{'data': <dynamic, dynamic>{'message': 'message'}};
61+
accessibilityAnnouncements.handleMessage(codec, codec.encodeMessage(testInput));
62+
final DomHTMLLabelElement input = domDocument.getElementById('accessibility-element')! as DomHTMLLabelElement;
63+
64+
expect(input.getAttribute('aria-live'), equals('polite'));
65+
});
66+
67+
test('aria-live is assertive when assertiveness is set to 1', () {
68+
const Map<dynamic, dynamic> testInput = <dynamic, dynamic>{'data': <dynamic, dynamic>{'message': 'message', 'assertiveness': 1}};
69+
accessibilityAnnouncements.handleMessage(codec, codec.encodeMessage(testInput));
70+
final DomHTMLLabelElement input = domDocument.getElementById('accessibility-element')! as DomHTMLLabelElement;
71+
72+
expect(input.getAttribute('aria-live'), equals('assertive'));
73+
});
74+
75+
test('aria-live is polite when assertiveness is null', () {
76+
const Map<dynamic, dynamic> testInput = <dynamic, dynamic>{'data': <dynamic, dynamic>{'message': 'message', 'assertiveness': null}};
77+
accessibilityAnnouncements.handleMessage(codec, codec.encodeMessage(testInput));
78+
final DomHTMLLabelElement input = domDocument.getElementById('accessibility-element')! as DomHTMLLabelElement;
79+
80+
expect(input.getAttribute('aria-live'), equals('polite'));
81+
});
82+
83+
test('aria-live is polite when assertiveness is set to 0', () {
84+
const Map<dynamic, dynamic> testInput = <dynamic, dynamic>{'data': <dynamic, dynamic>{'message': 'message', 'assertiveness': 0}};
85+
accessibilityAnnouncements.handleMessage(codec, codec.encodeMessage(testInput));
86+
final DomHTMLLabelElement input = domDocument.getElementById('accessibility-element')! as DomHTMLLabelElement;
87+
88+
expect(input.getAttribute('aria-live'), equals('polite'));
89+
});
5890
});
5991
}

0 commit comments

Comments
 (0)