Skip to content

Commit 082d787

Browse files
fix: stale VoiceOver value from async UI updates to Text (#58169)
Summary: This is a targeted fix for #58145, where I observed iOS VoiceOver reading stale values over `Text` elements that were updated asynchronously (from a `setTimeout` call). This patch definitely fixes the issue, but I'm happy to iterate on the design if there are any considerations I haven't taken into account: coolsoftwaretyler/focusissues#1 Maybe related to #49462? Although what I found is that when VoiceOver encountered a failure, it bounced back to the status bar, so it's possible 49462 is some *other* issue with modals that presents the same failure mode. ## Changelog: Pick one each for the category and type tags: [IOS] [FIXED] -VoiceOver text readout when changing elements asynchronously Pull Request resolved: #58169 Test Plan: I built a reproducer and tested this patch with it. To test: 1. Build reproducer (or any app that changes text asynchronously) 2. Install app to physical device (I found the accessibility inspector tool with simulators would paper over the issue, so you need to actually use VoiceOver on a device) 3. Turn on voiceover 4. Navigate through the interface, moving focus through your elements to ensure they work as expected 5. Then use VoiceOver to trigger an async update to some text 6. Move on to any value that was changed by the async update 7. Text will probably be stale, and moving focus no longer works ### Before https://github.com/user-attachments/assets/05b8d308-e743-4cff-917c-c5410307937d ### After https://github.com/user-attachments/assets/d7d8d3fc-5bd8-45b9-bab0-de9bbc9cbcda Reviewed By: cortinico Differential Revision: D117875865 Pulled By: christophpurrer fbshipit-source-id: 218ca244ea99e460d687ec527d6fbcaa9e499943
1 parent 671705d commit 082d787

1 file changed

Lines changed: 11 additions & 0 deletions

File tree

packages/react-native/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,17 @@ - (void)updateState:(const State::Shared &)state oldState:(const State::Shared &
138138
_textView.state = std::static_pointer_cast<const ParagraphShadowNode::ConcreteState>(state);
139139
[_textView setNeedsDisplay];
140140
[self setNeedsLayout];
141+
142+
// If the attributed string has changed, we need to notify the accessibility system that something changed,
143+
// otherwise it may hold on to stale values (this happens most often when an element is updated async)
144+
// https://github.com/react/react-native/issues/58145
145+
if (state && oldState) {
146+
const auto &newData = std::static_pointer_cast<const ParagraphShadowNode::ConcreteState>(state)->getData();
147+
const auto &oldData = std::static_pointer_cast<const ParagraphShadowNode::ConcreteState>(oldState)->getData();
148+
if (!newData.attributedString.isContentEqual(oldData.attributedString)) {
149+
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
150+
}
151+
}
141152
}
142153

143154
- (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics

0 commit comments

Comments
 (0)