react / react/react-native

iOS: nested Text with mixed fonts + lineHeight paints glyphs shifted/clipped under tail truncation — while onTextLayout/onLayout report correct positions

Open
#58,315 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Needs: Triage :mag: Platform: iOS
Dominant language
C++
Stars
127k
Forks
25.3k
Avg merge
1d 23h
Merged PRs (30d)
4

Description

Description

A one-line (Arabic, RTL) containing nested spans where one span uses a different font/size (a fallback-font run), with an explicit lineHeight, paints its glyphs vertically shifted and bottom-clipped when the line is tail-truncated on iOS. Untruncated rows with identical structure paint correctly. The shift worsens with scroll depth in a ScrollView.

Reproduces across fonts: dramatic with a mushaf-grade face (KFGQPC Hafs — glyphs sink and bottom-clip), subtle but present with Scheherazade New (descender marks such as hamza+kasra paint slightly low). Severity scales with how far the font's ink extents diverge from its nominal metrics.

Critically: the shift is invisible to the layout APIs. onLayout and onTextLayout report identical geometry for shifted and correct rows — the repro measures both and prints the delta, which reads 0.0px while the painted output visibly diverges (the label is kept as a negative control). The defect appears to sit between text layout and rendering.

Plain single-font rows, flat rows, narrow rows, and RTL-aligned rows all paint correctly (mutations M1–M3 in the repro, all Δ 0.0 and visually clean) — the mixed-font nested run (M4) is the trigger.

Possibly related: #19653 (baseline offset computed from largest font-height in the string), #53092 (nested Text misalignment with lineHeight under the New Architecture).

Screenshots (also in the repo README): truncated rows sinking/clipping under Hafs+M4 vs their fitting pair rows.

Steps to reproduce

Reproduces across fonts: dramatic with a mushaf-grade face (KFGQPC Hafs — glyphs sink and bottom-clip), subtle but present with Scheherazade New (descender marks such as hamza+kasra paint slightly low). Severity scales with how far the font's ink extents diverge from its nominal metrics.

  1. Clone https://github.com/muhasabahhub/rn-arabic-seat, npm install, npx expo start, open in Expo Go on a physical iPhone.
  2. Select: tail (stock) + Hafs (mushaf) + M4 mixed-run.
  3. Scroll the list. Rows come in pairs sharing their opening words — first fits, second truncates.
  4. Compare pairs against the red guide: truncated rows paint shifted/bottom-clipped, worsening with scroll depth.
  5. Note the Δ label reads 0.0px — onLayout/onTextLayout report identical seating while the paint diverges (negative control).
  6. Toggle M4 off (or fonts to Amiri): all rows paint correctly, Δ 0.0 and visually clean.
React Native Version

0.86.3

Affected Platforms

Runtime - iOS

Output of npx @react-native-community/cli info
Expo SDK 57 managed project — envinfo equivalent below; full dependency table in the repo README.

 System:
    OS: Windows 11 10.0.26200
    CPU: (22) x64 Intel(R) Core(TM) Ultra 7 155H
    Memory: 3.80 GB / 15.59 GB
  Binaries:
    Node: 24.13.1 - C:\Program Files\nodejs\node.EXE
    npm: 11.19.0 - C:\Program Files\nodejs\npm.CMD
  npmPackages:
    expo: ~57.0.18 => 57.0.19
    expo-font: ~57.0.2 => 57.0.3
    react: 19.2.3 => 19.2.3
    react-native: 0.86.3 => 0.86.3
    react-native-safe-area-context: ~5.7.0 => 5.7.0


Device: iPhone 15, iOS 23.3.1, physical device via Expo Go. New Architecture (Fabric), Hermes.
Stacktrace or Logs
No crash or error output — this is a silent rendering defect. Nothing is logged.

The relevant "log" is the measurement built into the repro itself: each row pair prints a Δ label computed from onLayout + onTextLayout. For visibly shifted rows, the APIs report Δ 0.0px — i.e. the layout system emits no signal that the painted output has diverged. Sample readout while the defect is visible on screen:

  pair 3 (Hafs, tail, M4): reported Δ 0.0px — painted output shifted and bottom-clipped (screenshot 1)
  pair 5 (Hafs, tail, M4): reported Δ 0.0px — painted output shifted, worsens with scroll depth (screenshot 2)

The absence of any discrepancy in the layout events is part of the report: the defect is undetectable programmatically from the JS layer.
MANDATORY Reproducer

https://github.com/muhasabahhub/rn-arabic-seat

Screenshots and Videos
Image

Contributor guide

Open the contributing guide

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 with the mandatory rn-arabic-seat reproducer, run it on a physical iPhone, and compare tail-truncated M4 rows using Hafs or Scheherazade New with the fitting control rows. No React Native source file or test is named; done means the mixed-font RTL rows no longer paint shifted or bottom-clipped under tail truncation while the reported layout geometry remains correct.

Written by the indexing model from the issue text.

Assessment

Tech stack
ios, 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.