Skip to content

Add android_lineBreakStyle and android_lineBreakWordStyle to Text - #59002

Open
iray-tno wants to merge 2 commits into
react:mainfrom
iray-tno:claude/react-native-changes-8rvmxi
Open

iray-tno wants to merge 2 commits into
react:mainfrom
iray-tno:claude/react-native-changes-8rvmxi

Conversation

@iray-tno

@iray-tno iray-tno commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary:

Android 13 (API 33) added LineBreakConfig, which controls two things CJK text needs and React Native cannot reach today:

  • Line-break strictness (LINE_BREAK_STYLE_LOOSE | NORMAL | STRICT) — CSS line-break. Strict kinsoku keeps characters such as small kana (ッ, ャ) and ー off the start of a line.
  • Phrase-based breaking (LINE_BREAK_WORD_STYLE_PHRASE) — CSS word-break: auto-phrase. Japanese breaks at phrase (文節) boundaries instead of between any two characters, which reads much better in short lines such as buttons and headings.

This cannot be done from a library. React Native builds the StaticLayout that both measures text for Yoga and is drawn, inside TextLayoutManager. A native module can only change the drawn TextView, which then disagrees with the measured height (clipped or extra lines). So the setting has to go through React Native's own text pipeline.

This PR adds two Android-only paragraph props, plumbed exactly like the existing android_hyphenationFrequency:

android_lineBreakStyle?: 'none' | 'loose' | 'normal' | 'strict'
android_lineBreakWordStyle?: 'none' | 'phrase'
  • JS / types: TextProps, TextNativeComponent view config, Text.d.ts, regenerated ReactNativeApi.d.ts.
  • C++: LineBreakStyle / LineBreakWordStyle enums, conversions, ParagraphAttributes fields (equality, hash, debug props), BaseParagraphProps parsing, Android props diffing, and two new paragraph MapBuffer keys. C++ API snapshots regenerated.
  • Android, measurement: TextLayoutManager applies the config to the StaticLayout.Builder on API 33+.
  • Android, drawing: ReactTextViewManager @ReactProp setters apply the same values to ReactTextView, so drawing matches measurement; recycled views reset them.

Behavior is unchanged unless the props are set. When both are 'none' (the default) no LineBreakConfig is set at all, and below API 33 the props are ignored. iOS has no equivalent API, so this is Android-only, like android_hyphenationFrequency.

'phrase' depends on locale. Per the Android docs, it has no effect in a locale without phrase-based breaking. Android Text is laid out in the device locale, so in practice it takes effect only when that locale supports it (e.g. Japanese). The prop docs say so. TextInput is intentionally left out to keep the change reviewable.

Motivation and design notes: iray-tno/hozo#813

Open question for reviewers — naming. I used the android_ prefix to match android_hyphenationFrequency, the sibling paragraph prop this mirrors. lineBreakStyleAndroid (matching lineBreakStrategyIOS) is the other option; happy to rename.

Changelog:

[ANDROID] [ADDED] - Add android_lineBreakStyle and android_lineBreakWordStyle props to Text for strict/loose line breaking and phrase-based breaking on Android 13+

Test Plan:

Ran locally:

  • yarn flow-check — 0 errors
  • yarn build-types then yarn test-generated-typescript — passes
  • yarn test — 241 suites, 6130 tests passed
  • yarn format-check-{javascript,cpp,kotlin,java} — clean
  • yarn cxx-api-validate (Doxygen 1.16.1, as in CI) — all 12 snapshots match; before regenerating, the 3 *FrameworksCxx.api snapshots failed
  • ESLint on the changed JS files — clean

Added:

  • C++ unit tests in ParagraphAttributesTest.cpp (equality/hash include the new fields, defaults are None, toString values match the JS prop values).
  • Updated the existing Robolectric tests that call TextLayoutManager internals for the new parameters. They pass NONE only, so they cover the plumbing, not the effect of strict / phrase.
  • RNTester: Text → Line break style shows the same Japanese paragraph under each value at a fixed width, with a background so any measurement/drawing mismatch is visible.

Not run locally: native compilation (Kotlin/Java/C++), the C++ and Robolectric unit tests, and an on-device check. The environment had no Android SDK and Gradle could not resolve its plugins. Relying on CI for the native build and tests.

Still to verify on device, with the RNTester example:

  • API 33+, Japanese device locale: strict / loose and phrase change the break positions
  • Measured height matches the drawn lines for each value (no clipped or blank lines)
  • Removing the prop returns to the default layout
  • A recycled Text does not keep a previous value
  • Non-Japanese device locale: phrase has no effect, and nothing breaks
  • API 31/32: the props are ignored

🤖 Generated with Claude Code

iray-tno and others added 2 commits October 9, 2026 13:39
Android 13 (API 33) added LineBreakConfig, which selects the
strictness of the line-breaking rules (CSS `line-break`: loose,
normal, strict) and phrase-based breaking for Japanese (CSS
`word-break: auto-phrase`). React Native measures and draws Text with
a StaticLayout it builds itself, so neither setting can be reached from
outside: a native module could only change the drawn TextView, which
would then disagree with the height Yoga measured.

Add two Android-only paragraph props, plumbed the same way as
android_hyphenationFrequency:

- android_lineBreakStyle: 'none' | 'loose' | 'normal' | 'strict'
- android_lineBreakWordStyle: 'none' | 'phrase'

They go into ParagraphAttributes and the paragraph MapBuffer, are
applied to the StaticLayout.Builder in TextLayoutManager (measurement
and the prepared layout), and to ReactTextView through @ReactProp
setters (drawing). Both are ignored below API 33. When both are
'none' (the default) no LineBreakConfig is set, so existing text lays
out exactly as before.

TextInput is left out: it does not list the props in its view config.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Regenerate the Frameworks C++ API snapshots (Common, Android, Apple)
for the new LineBreakStyle and LineBreakWordStyle enums, their
conversions, the ParagraphAttributes fields and the paragraph
MapBuffer keys. Generated with `yarn cxx-api-build` using Doxygen
1.16.1, the version the validation workflow pins.

Document that android_lineBreakWordStyle="phrase" depends on the
locale: Android Text is laid out in the device locale, and where that
locale has no phrase-based breaking the setting has no effect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 12, 2026
@github-actions

Copy link
Copy Markdown

Warning

JavaScript API change detected

This PR commits an update to ReactNativeApi.d.ts, indicating a change to React Native's public JavaScript API.

  • Please include a clear changelog message.
  • This change will be subject to additional review.

This change was flagged as: POTENTIALLY_BREAKING

@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Oct 12, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant