software-mansion / software-mansion/react-native-enriched-html

Text immediately before an `<img>` sometimes fails to repaint on iOS after a screen revisit (`EnrichedText`)

Open
#798 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
C
Stars
1.4k
Forks
66
Avg merge
4d 19h
Merged PRs (30d)
11

Description

Describe the bug
When EnrichedText renders HTML containing an <img>, the text on the line immediately before that image can fail to visually paint on iOS. The text is still present and correctly positioned (confirmed via the accessibility tree), but it never gets drawn. The rest of the surrounding content renders fine.

This issue is specifically correlated with revisiting a screen via React Navigation (@react-navigation/native + react-native-screens native-stack, via expo-router). A fresh first visit renders correctly, but navigating away and then back causes the line to reliably or intermittently fail to paint. This is an iOS-only issue and does not reproduce on Android.

Investigation ruled out JS-side remount timing issues (the bug persists even with zero remounts/key changes on revisit, or when forcing fixed-delay remounts).

To Reproduce
Steps to reproduce the behavior:

  1. In an app using expo-router or @react-navigation/native (with react-native-screens), create a screen that renders EnrichedText.
  2. Provide HTML ending in a text block immediately followed by an <img>, e.g., ...<div>Some text</div><img src="..." width="..." height="..." />.
  3. Navigate to that screen. (Observe that it renders correctly).
  4. Navigate back to the previous screen.
  5. Navigate forward to the same screen again.
  6. See error: The line of text immediately before the <img> is now blank (though still present and correctly positioned in the accessibility tree).

Expected behavior
The text immediately preceding the <img> tag should consistently paint and remain visible on subsequent visits to the screen, mirroring the behavior of the initial visit.

Screenshots
(Not applicable/No screenshot provided — visually, it manifests as empty space where the text should be).

Device (please complete the following information):

  • Device: iPhone 17 Pro (iOS Simulator)
  • OS: iOS 26.4
  • Version: react-native-enriched-html v1.1.1 (Running on React Native 0.86.3, Expo ~57.0.20, Fabric new architecture)

Additional context
Reproduction context: This issue could not be reproduced in isolation (e.g., via a Storybook story with identical HTML and remount behavior). It strictly depends on real React Navigation transition/view-controller behavior.

Potential contributing factor identified: In EnrichedTextView.mm, renderContent fully rebuilds textView.textStorage on every render but never explicitly invalidates/re-lays-out the NSLayoutManager around the changed content. This contrasts with the editable EnrichedTextInputView.mm, which works around similar TextKit gaps via _performRelayout. Patching EnrichedTextView to mirror this sequence did not reliably fix this specific bug on its own, but it highlights a potential TextKit gap.

Questions for maintainers:

  • Is there a known interaction between EnrichedTextView's render/layout cycle and view controller appearance/reappearance (e.g., viewWillAppear/native view recycling) that could cause a stale/incomplete TextKit layout pass specifically on a view's second-or-later appearance in a navigation stack?
  • Are there any existing instrumentation or debug flags in the library for tracing NSLayoutManager invalidation timing to help build a tighter reproduction?

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in EnrichedTextView.mm, especially renderContent, and compare its textStorage and layout handling with EnrichedTextInputView.mm and _performRelayout. Reproduce the issue through expo-router or React Navigation with react-native-screens by leaving and revisiting the screen on iOS. Done means text immediately before an consistently paints on subsequent visits without regressing initial rendering.

Written by the indexing model from the issue text.

Assessment

Tech stack
ios, objective-c, react-native
Domain
mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.