Description
On ColorOS 15 (Realme / OPPO), textAlign: "justify" on a plain <Text> renders
left-aligned. There is no error, no warning and no fallback — the app has no way to know
justification did not happen.
React Native itself does the right thing. TextLayoutManager.getTextJustificationMode()
maps the "justified" alignment attribute to Layout.JUSTIFICATION_MODE_INTER_WORD, and
createLayout() passes it to StaticLayout.Builder.setJustificationMode() on API >= 26.
The OEM text engine accepts the call and does not apply it.
This is not the New Architecture path: enablePreparedTextLayout defaults to false, so
this goes through the shared ReactTextView / StaticLayout route.
It is also not a library, font or styling problem. I tested 13 variants on both devices —
bare justify, textBreakStrategy simple/highQuality/balanced, with and without
lineHeight, four fonts (system default, sans-serif, and two bundled asset fonts),
includeFontPadding: false, android_hyphenationFrequency: "normal", and nested <Text>.
- Stock Android: all 13 justify correctly.
- ColorOS 15: none justify, including the simplest possible case — a plain
<Text>
with only fontSize and textAlign: "justify", no custom font and no other styling.
A textAlign: "left" control was included throughout and correctly reads unjustified on
both devices, confirming the measurement distinguishes the two states.
Why this is worth an RN-level issue even though the root cause is the OEM: apps
currently have no way to detect that justification was dropped, so the only options are an
OEM allowlist or shipping silently broken layout. Either a way to query whether
justification was actually applied, or a documented caveat on textAlign, would let apps
fall back deliberately.
Steps to reproduce
-
Clone and install the reproducer:
git clone https://github.com/ilalgtc/ColorOSJustifyRepro.git
cd ColorOSJustifyRepro
npm install
-
Run it on a ColorOS 15 device (tested: Realme RMX3686, Android 15, API 35):
npx react-native run-android
Everything is in App.tsx. There is one screen and no extra dependency.
-
Read the summary line at the top of the screen. On ColorOS it reports:
JUSTIFIED on this device: none
-
Look at probe A — a plain <Text> with only fontSize and
textAlign: "justify", no custom font, no HTML renderer, no third-party library.
It renders left-aligned with a ragged right edge and reports NOT JUSTIFIED,
with a shortfall of tens of px against the container.
-
Run the same build on stock Android (an emulator is enough). The summary line
reports:
JUSTIFIED on this device: A, B, C, D, E, F, G
and probe A renders flush to both margins, reporting shortfall 0.0px.
Each probe renders the same paragraph in the same container and measures itself via
onTextLayout, so the screen prints its own verdict — nothing has to be judged by eye.
Probe Z is a control using textAlign: "left". It must read NOT JUSTIFIED on
every device, including stock Android. It is there to prove the measurement can tell
the two states apart rather than always reporting "justified" — if Z ever reads
JUSTIFIED, the measurement is broken and the app says so on screen.
React Native Version
0.87.1
Affected Platforms
Runtime - Android
Output of npx @react-native-community/cli info
System:
OS: macOS 26.3
CPU: (8) arm64 Apple M2
Memory: 123.92 MB / 16.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 24.3.0
path: /Users/kaushal/.nvm/versions/node/v24.3.0/bin/node
Yarn:
version: 1.22.22
path: /opt/homebrew/bin/yarn
npm:
version: 11.4.2
path: /Users/kaushal/.nvm/versions/node/v24.3.0/bin/npm
Watchman:
version: 2026.01.12.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.16.2
path: /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 25.2
- iOS 26.2
- macOS 26.2
- tvOS 26.2
- visionOS 26.2
- watchOS 26.2
Android SDK: Not Found
IDEs:
Android Studio: 2026.1 AI-261.26222.65.2613.16025427
Xcode:
version: 26.2/17C52
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.18
path: /usr/bin/javac
Ruby:
version: 2.6.10
path: /usr/bin/ruby
npmPackages:
"@react-native-community/cli":
installed: 20.2.0
wanted: 20.2.0
react:
installed: 19.2.3
wanted: 19.2.3
react-native:
installed: 0.87.1
wanted: 0.87.1
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: Not found
newArchEnabled: false
Stacktrace or Logs
No crash. This is a rendering/layout defect, so the "log" is the line geometry the
reproducer measures with onTextLayout and prints on screen.
Reproducer: probe A = <Text style={{ fontSize: 16, textAlign: "justify" }}>
Probe Z = the same text with textAlign: "left" (control)
React Native 0.87.1, new architecture enabled.
--- Emulator, stock Android 16 (API 36) -----------------------------------------
Summary line: "JUSTIFIED on this device: A, B, C, D, E, F, G"
A (justify only) box 394.7 · 12 lines · shortfall 0.0px · overflow 4.3px
widths 398.6, 395.9, 397.5, 398.6, 398.9, 397.2, ...
Z (control, left) box 394.7 · 12 lines · shortfall 41.8px · overflow 0.0px
widths 352.9, 369.4, 358.6, 385.5, 354.9, 376.7, ...
Probes B-G report identical geometry to A. The control behaves as expected.
--- Realme RMX3686, ColorOS 15, Android 15 (API 35) -----------------------------
Summary line: "JUSTIFIED on this device: none"
A (justify only) box <FILL> · <FILL> lines · shortfall <FILL>px · overflow <FILL>px
widths <FILL>
Z (control, left) box <FILL> · <FILL> lines · shortfall <FILL>px · overflow <FILL>px
widths <FILL>
---------------------------------------------------------------------------------
Probe A on ColorOS measures tens of px short and its line widths vary line to line —
the signature of left-aligned text — while the identical probe on stock Android is
flush to within 0.0px. Probe Z is unjustified on both, confirming the measurement
separates the two states rather than always reporting "justified".
Secondary observation: where justification does work, lines measure ~4px WIDER than
their container (overflow 4.3px above), which clips the trailing glyph. Visible on
stock Android too and independent of the ColorOS problem.
MANDATORY Reproducer
https://github.com/kaushaldarji29/ColorOSJustifyRepro
Screenshots and Videos

Description
On ColorOS 15 (Realme / OPPO),
textAlign: "justify"on a plain<Text>rendersleft-aligned. There is no error, no warning and no fallback — the app has no way to know
justification did not happen.
React Native itself does the right thing.
TextLayoutManager.getTextJustificationMode()maps the
"justified"alignment attribute toLayout.JUSTIFICATION_MODE_INTER_WORD, andcreateLayout()passes it toStaticLayout.Builder.setJustificationMode()on API >= 26.The OEM text engine accepts the call and does not apply it.
This is not the New Architecture path:
enablePreparedTextLayoutdefaults tofalse, sothis goes through the shared
ReactTextView/StaticLayoutroute.It is also not a library, font or styling problem. I tested 13 variants on both devices —
bare justify,
textBreakStrategysimple/highQuality/balanced, with and withoutlineHeight, four fonts (system default,sans-serif, and two bundled asset fonts),includeFontPadding: false,android_hyphenationFrequency: "normal", and nested<Text>.<Text>with only
fontSizeandtextAlign: "justify", no custom font and no other styling.A
textAlign: "left"control was included throughout and correctly reads unjustified onboth devices, confirming the measurement distinguishes the two states.
Why this is worth an RN-level issue even though the root cause is the OEM: apps
currently have no way to detect that justification was dropped, so the only options are an
OEM allowlist or shipping silently broken layout. Either a way to query whether
justification was actually applied, or a documented caveat on
textAlign, would let appsfall back deliberately.
Steps to reproduce
Clone and install the reproducer:
Run it on a ColorOS 15 device (tested: Realme RMX3686, Android 15, API 35):
Everything is in
App.tsx. There is one screen and no extra dependency.Read the summary line at the top of the screen. On ColorOS it reports:
Look at probe A — a plain
<Text>with onlyfontSizeandtextAlign: "justify", no custom font, no HTML renderer, no third-party library.It renders left-aligned with a ragged right edge and reports
NOT JUSTIFIED,with a shortfall of tens of px against the container.
Run the same build on stock Android (an emulator is enough). The summary line
reports:
and probe A renders flush to both margins, reporting
shortfall 0.0px.Each probe renders the same paragraph in the same container and measures itself via
onTextLayout, so the screen prints its own verdict — nothing has to be judged by eye.Probe Z is a control using
textAlign: "left". It must readNOT JUSTIFIEDonevery device, including stock Android. It is there to prove the measurement can tell
the two states apart rather than always reporting "justified" — if Z ever reads
JUSTIFIED, the measurement is broken and the app says so on screen.React Native Version
0.87.1
Affected Platforms
Runtime - Android
Output of
npx @react-native-community/cli infoStacktrace or Logs
MANDATORY Reproducer
https://github.com/kaushaldarji29/ColorOSJustifyRepro
Screenshots and Videos