React Native: nested Text for inline / paragraph layout
When to suspect this issue
Symptoms often look like font or theme bugs but are really layout mode:
- Line height or vertical rhythm looks wrong vs the same styles on a single
Text - Wrapped lines have uneven gaps, odd baselines, or "extra" space above/below
letterSpacingor transforms look different from a normal paragraph- Tweaking
lineHeight,padding, ormarginhelps only a little or not at all
Common trigger code: each glyph is its own Text / Animated.Text wrapped in View with flexDirection: "row" and flexWrap: "wrap" (sometimes one View per word).
That structure is flex layout of boxes, not the text layout engine. Breaks, baselines, and multi-line spacing will not match a real paragraph.
Fix: one parent Text, nested children
Put one outer Text (or Animated.Text if the whole block is animated) around the fragments. Nested Text / Animated.Text children lay out inline, share wrapping, and match normal typography.
- Apply paragraph styles (
fontSize,lineHeight,fontFamily,color,letterSpacing,textTransform, etc.) on the parent when possible; children inherit unless overridden. - Each animated character stays an
Animated.Textchild without duplicating full paragraph styles if inheritance is enough.
Do not use Fragment inside Text
React Native Text children must be Text nodes or strings. Build arrays with flatMap / spread instead of <>...</>.
Example shape (character stagger)
<Text style={paragraphStyle}>
{words.flatMap((word, wordIndex) => {
const keys = word.split("").map((char, i) => (
<Animated.Text key={`${wordIndex}-${i}`} entering={/* ... */}>
{char}
</Animated.Text>
));
if (wordIndex < words.length - 1) {
return [
...keys,
<Animated.Text key={`sp-${wordIndex}`} entering={/* ... */}>
{"\u00A0"}
</Animated.Text>,
];
}
return keys;
})}
</Text>Words can be precomputed with useMemo if needed; keep keys stable.
Related gotchas
- Android:
includeFontPaddingon the parentTextcan tighten vertical metrics if labels still look vertically padded. - Layout reservation: If a hidden placeholder and visible control differ in copy or line count (e.g. two button labels), height can shift when swapping; use the same final string (or explicit
minHeight) for the placeholder. - Still wrong? After nested
Text, if top inset looks off, check navigator header +SafeAreaView(e.g. double top inset with a transparent stack header), not typography.
Quick checklist
- Is per-character (or per-word-for-wrap) content inside Views + flexWrap? → Refactor to parent
Text+ nestedText/Animated.Text. - Are paragraph styles on the parent so inheritance is consistent?
- No
FragmentinsideText; use array /flatMap. - Placeholder vs visible text: same dimensions?