Skip to content

Commit 4851fb2

Browse files
maxencehenneronmeta-codesync[bot]
authored andcommitted
Add support for UIAccessibilityPriority (#54289)
Summary: Adds support for UIAccessibilityPriority on iOS. This is important because we want to be able to set high-priority announcements that cannot be interrupted. Use case: a modal opens, user performs an action that closes the modal and returns to the previous page. We need to announce it but the voiceover engine will target an element as we've just navigated and cancel the announcement because the default announcement priority is interruptible. https://developer.apple.com/videos/play/wwdc2023/10036/?time=293 Here's a talk about this in wwdc 2023. <img width="1813" height="981" alt="Screenshot 2025-10-27 at 11 12 18" src="https://github.com/user-attachments/assets/8306d6f6-a5a9-4834-a5d9-c5b2e014c258" /> ## Changelog: [IOS][ADDED] - Add support for UIAccessibilityPriority in announcements Pull Request resolved: #54289 Test Plan: Open the rn-tester app, go to Accessibility -> Check if the screen reader announces. Press: Announce for accessibility High Priority. You will hear "High Priority Announcement Test, Normal Priority Announcement". The second announcement did not cancel the first announcement (expected behavior) Press: Announce for accessibility Low Priority: You will only hear "Normal Priority Announcement". The low priority announcement was successfully interrupted. Reviewed By: cipolleschi Differential Revision: D87477523 Pulled By: javache fbshipit-source-id: 5e8ccf26188cce1407cb814df6993fcbf1ade7ce
1 parent 7a66582 commit 4851fb2

File tree

6 files changed

+82
-5
lines changed

6 files changed

+82
-5
lines changed

packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.d.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,18 @@ export interface AccessibilityInfoStatic {
150150
* - `announcement`: The string announced by the screen reader.
151151
* - `options`: An object that configures the reading options.
152152
* - `queue`: The announcement will be queued behind existing announcements. iOS only.
153+
* - `priority`: The priority of the announcement. Possible values: 'low' | 'default' | 'high'.
154+
* High priority announcements will interrupt any ongoing speech and cannot be interrupted.
155+
* Default priority announcements will interrupt any ongoing speech but can be interrupted.
156+
* Low priority announcements will not interrupt ongoing speech and can be interrupted.
157+
* (iOS only).
153158
*/
154159
announceForAccessibilityWithOptions(
155160
announcement: string,
156-
options: {queue?: boolean | undefined},
161+
options: {
162+
queue?: boolean | undefined;
163+
priority?: 'low' | 'default' | 'high' | undefined;
164+
},
157165
): void;
158166

159167
/**

packages/react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,10 +476,15 @@ const AccessibilityInfo = {
476476
* - `announcement`: The string announced by the screen reader.
477477
* - `options`: An object that configures the reading options.
478478
* - `queue`: The announcement will be queued behind existing announcements. iOS only.
479+
* - `priority`: The priority of the announcement. Possible values: 'low' | 'default' | 'high'.
480+
* High priority announcements will interrupt any ongoing speech and cannot be interrupted.
481+
* Default priority announcements will interrupt any ongoing speech but can be interrupted.
482+
* Low priority announcements will not interrupt ongoing speech and can be interrupted.
483+
* (iOS only).
479484
*/
480485
announceForAccessibilityWithOptions(
481486
announcement: string,
482-
options: {queue?: boolean},
487+
options: {queue?: boolean, priority?: 'low' | 'default' | 'high'},
483488
): void {
484489
if (Platform.OS === 'android') {
485490
NativeAccessibilityInfoAndroid?.announceForAccessibility(announcement);

packages/react-native/React/CoreModules/RCTAccessibilityManager.mm

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,11 +325,28 @@ static void setMultipliers(
325325
announceForAccessibilityWithOptions : (NSString *)announcement options : (
326326
JS::NativeAccessibilityManager::SpecAnnounceForAccessibilityWithOptionsOptions &)options)
327327
{
328-
NSMutableDictionary<NSString *, NSNumber *> *attrsDictionary = [NSMutableDictionary new];
328+
NSMutableDictionary<NSString *, id> *attrsDictionary = [NSMutableDictionary new];
329329
if (options.queue()) {
330330
attrsDictionary[UIAccessibilitySpeechAttributeQueueAnnouncement] = @(*(options.queue()) ? YES : NO);
331331
}
332332

333+
if (options.priority() != nil) {
334+
NSString *priorityString = options.priority();
335+
if (@available(iOS 17.0, *)) {
336+
NSString *priorityValue = nil;
337+
if ([priorityString isEqualToString:@"low"]) {
338+
priorityValue = UIAccessibilityPriorityLow;
339+
} else if ([priorityString isEqualToString:@"default"]) {
340+
priorityValue = UIAccessibilityPriorityDefault;
341+
} else if ([priorityString isEqualToString:@"high"]) {
342+
priorityValue = UIAccessibilityPriorityHigh;
343+
}
344+
if (priorityValue != nil) {
345+
attrsDictionary[UIAccessibilitySpeechAttributeAnnouncementPriority] = priorityValue;
346+
}
347+
}
348+
}
349+
333350
if (attrsDictionary.count > 0) {
334351
NSAttributedString *announcementWithAttrs = [[NSAttributedString alloc] initWithString:announcement
335352
attributes:attrsDictionary];

packages/react-native/ReactNativeApi.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<c619aadf59837a8cefb13f7cc4e4c139>>
7+
* @generated SignedSource<<226d64917d955b2d515d33b38d74f12e>>
88
*
99
* This file was generated by scripts/js-api/build-types/index.js.
1010
*/
@@ -104,6 +104,7 @@ declare const AccessibilityInfo_default: {
104104
announceForAccessibilityWithOptions(
105105
announcement: string,
106106
options: {
107+
priority?: "default" | "high" | "low"
107108
queue?: boolean
108109
},
109110
): void

packages/react-native/src/private/specs_DEPRECATED/modules/NativeAccessibilityManager.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export interface Spec extends TurboModule {
6363
+announceForAccessibility: (announcement: string) => void;
6464
+announceForAccessibilityWithOptions?: (
6565
announcement: string,
66-
options: {queue?: boolean},
66+
options: {queue?: boolean, priority?: 'low' | 'default' | 'high'},
6767
) => void;
6868
}
6969

packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,44 @@ class AnnounceForAccessibility extends React.Component<{}> {
12931293
);
12941294
};
12951295

1296+
_handleOnPressHighPriority = () => {
1297+
setTimeout(
1298+
() =>
1299+
AccessibilityInfo.announceForAccessibilityWithOptions(
1300+
'High Priority Announcement Test',
1301+
{priority: 'high'},
1302+
),
1303+
1000,
1304+
);
1305+
1306+
setTimeout(
1307+
() =>
1308+
AccessibilityInfo.announceForAccessibility(
1309+
'Normal Priority Announcement',
1310+
),
1311+
1100,
1312+
);
1313+
};
1314+
1315+
_handleOnPressLowPriority = () => {
1316+
setTimeout(
1317+
() =>
1318+
AccessibilityInfo.announceForAccessibilityWithOptions(
1319+
'Low Priority Announcement Test',
1320+
{priority: 'low'},
1321+
),
1322+
1000,
1323+
);
1324+
1325+
setTimeout(
1326+
() =>
1327+
AccessibilityInfo.announceForAccessibility(
1328+
'Normal Priority Announcement',
1329+
),
1330+
1100,
1331+
);
1332+
};
1333+
12961334
render(): React.Node {
12971335
return Platform.OS === 'ios' ? (
12981336
<View>
@@ -1308,6 +1346,14 @@ class AnnounceForAccessibility extends React.Component<{}> {
13081346
onPress={this._handleOnPressQueueMultiple}
13091347
title="Announce for Accessibility Queue Multiple"
13101348
/>
1349+
<Button
1350+
onPress={this._handleOnPressHighPriority}
1351+
title="Announce for Accessibility High Priority"
1352+
/>
1353+
<Button
1354+
onPress={this._handleOnPressLowPriority}
1355+
title="Announce for Accessibility Low Priority"
1356+
/>
13111357
</View>
13121358
) : (
13131359
<View>

0 commit comments

Comments
 (0)