[iOS][Fabric] numberOfLines={1} with CJK text collapses to first character + ellipsis when tail truncation is required (0.86.0)
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 52/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- ios, react-native
- Domain
- mobile
Research direction
Start by reproducing the CJK bracket case on a physical iOS device with RN 0.86.0, then inspect the Fabric tail-truncation path, including processTruncatedAttributedText and related issues #57499 and #57501. Done means the failing string fills the available width before tail ellipsizing while the listed control cases remain correct.
Written by the indexing model from the issue text.
Description
Description
On iOS with the New Architecture (RN 0.86.0), <Text numberOfLines={1}> collapses to just the first character + ellipsis (e.g. 中文标题(银色示例、金色文字) → 中...) when all of the following hold:
- the string needs tail truncation (wider than the container), and
- the string contains a full-width bracket pair
(…), and - the string ends with the closing bracket
).
Line wrapping of the same string (no numberOfLines) breaks at exactly the container edge, and middle / head / clip ellipsization all work — only the tail truncation path collapses. Android renders all cases correctly.
Minimal reproducer
No flex involved — a fixed-width box is enough:
import React from 'react';
import { View, Text } from 'react-native';
const CASES = [
'中文标题(银色示例、金色文字)', // ❌ BUG: renders as 中... (first char + ellipsis)
'中文标题(银色示例、金色文字)字', // ✅ same + 1 trailing han char: truncates correctly
'一段较长的中文标题文字内容例)', // ✅ unpaired closing bracket: correct
'一段较长的中文标题文字内容示例。', // ✅ ends with full-width period: correct
'Mechanical watch gold (silver)', // ✅ ASCII closing paren: correct
];
export default function App() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<View style={{ width: 240, borderWidth: 1 }}>
{CASES.map((s, i) => (
<Text key={i} numberOfLines={1} style={{ fontSize: 17 }}>
{s}
</Text>
))}
</View>
</View>
);
}
Reproducer: Open in Expo Snack (iOS) — same code as above, loaded via the Snack code URL parameter.
Evidence / trigger characterization
Measured on device via onTextLayout (lines[0].width, container 240pt, fontSize 17):
| String | Shape | lines[0].width | Result |
|---|---|---|---|
中文标题(银色示例、金色文字) |
bracket pair, ends with ) |
34 | ❌ collapses to 中... |
中文标题(银色示例、金色文字)字 |
same + trailing han char | 231 | ✅ |
一段较长的中文标题文字内容例) |
) at end, no opening ( |
236 | ✅ |
一段较长的中文标题文字内容示例。 |
ends with 。 |
236 | ✅ |
Mechanical watch gold (silver) |
ASCII ) at end |
231 | ✅ |
一段较长的中文标题文字内容示例 |
pure han, slight overflow | 236 | ✅ |
| long CJK strings overflowing by a lot (with or without brackets mid-string) | — | ~236 | ✅ |
Further observations for the failing case:
onTextLayoutreports a single line whosetextis the full string but whosewidthis ≈ 34pt (first glyph + ellipsis), whileonLayoutof the<Text>reports the correct frame width (240pt).- Without
numberOfLines, the same string wraps at exactly the container edge — line breaking is correct; only tail truncation collapses. ellipsizeMode="middle" | "head" | "clip"all render correctly for the same string.- Independent of font weight, explicit
lineHeight,lineBreakStrategyIOS(none/standard), and layout context (fixed-width box, flex column, flex row all reproduce identically). - Android (same JS) renders all cases correctly.
Expected behavior
Fills the available width before ellipsizing, e.g. 中文标题(银色示例、金色... — as Android does.
Actual behavior
Renders 中... (first character + ellipsis) with the rest of the 240pt frame empty.
Workaround
Platform-gate the ellipsize mode for potentially-CJK single-line text: ellipsizeMode={Platform.OS === "ios" ? "middle" : "tail"}.
Version / environment
- react-native 0.86.0 (New Architecture / Fabric), Hermes
- Reproduces: physical iPhone on iOS 26.5.2 — both in an Expo SDK 57 development client (RN 0.86.0) and in Expo Go (SDK 57) opening the Snack above
- Does NOT reproduce: the same Snack in Snack's embedded iOS simulator — but note that the embedded simulator only offers SDK 54 (RN 0.81.x) (SDK 55 is listed but errors out), so this contrast varies both the RN version and the OS version and cannot isolate which one matters
- Interpretation: the non-repro on the SDK 54 simulator is consistent with a regression introduced somewhere in RN 0.82–0.86 (e.g. the truncation-pipeline changes), but an iOS 26.x TextKit behavior change cannot be excluded either — we have no second iOS device/OS to separate the two
- Android with the same JS is unaffected
Possibly related
- #57499 (NSRangeException in
processTruncatedAttributedText— same truncation pipeline) - #57501 (clipping of last-line orphan token without
numberOfLines— possibly the same backtracking logic)
- Dominant language
- C++
- Stars
- 127k
- Forks
- 25.3k
- PR merge metrics
- No merged PRs in 30d
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from react/react-native
-
Needs: Author Feedback Needs: Repro
Difficulty 1/5 Under an hour Newbie friendliness 92/100
react/react-native#58621 · 1 comment ·
-
Needs: Author Feedback Needs: Repro
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
react/react-native#58610 · 1 comment ·
-
Needs: Triage :mag:
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
react/react-native#58565 · 1 comment · 2 reactions ·
-
Needs: Author Feedback Needs: Repro
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
react/react-native#58555 · 5 comments · 2 reactions ·
-
Needs: Attention Needs: Repro
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
react/react-native#58526 · 2 comments ·
All issues in react/react-native
Similar issues
-
ai_reviewed
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
ydb-platform/ydb#53869 · 3 comments ·
-
bug cert blocker needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
project-chip/connectedhomeip#74373 ·
-
upstream update
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
conan-io/conan-center-index#31035 ·
-
Bug
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
documentation
Difficulty 1/5 Under an hour Newbie friendliness 85/100
vllm-project/vllm-ascend#17329 ·