fix(ios): center TextInput text when lineHeight > fontSize on Fabric#56487
Open
janicduplessis wants to merge 2 commits intofacebook:mainfrom
Open
fix(ios): center TextInput text when lineHeight > fontSize on Fabric#56487janicduplessis wants to merge 2 commits intofacebook:mainfrom
janicduplessis wants to merge 2 commits intofacebook:mainfrom
Conversation
606f1d7 to
4e79973
Compare
4e79973 to
bf72714
Compare
|
Looking for it |
9bcb81f to
c73a582
Compare
acf8672 to
e4b8473
Compare
|
Warning JavaScript API change detected This PR commits an update to
This change was flagged as: |
99c3b8b to
156b724
Compare
…ht > fontSize On iOS, when a TextInput's lineHeight exceeds its font's line height, UIKit anchors glyphs to the bottom of the attributed-string line box instead of centering them within it. The same misalignment affects the placeholder. On single-line UITextField the caret is also sized to the full line box. This patch fixes all three surfaces. The approach varies by UIKit rendering path: UITextView (multi-line) typed text — honors NSBaselineOffsetAttributeName. Call RCTApplyBaselineOffset in RCTTextInputComponentView._setAttributedString: to inject the offset. Re-seed NSParagraphStyleAttributeName from defaultTextAttributes on ranges missing it (or carrying a zero-line-height stub), because UIKit's typingAttributes drops the paragraph style between keystrokes — without the re-seed the helper sees maximumLineHeight == 0 and bails for typed content. UITextField (single-line) typed text — does NOT honor NSBaselineOffsetAttributeName. Per-range zero out paragraphStyle.minimumLineHeight / maximumLineHeight on the displayed attributedText so UITextField uses the font's natural line height; its built-in vertical centering then positions the glyph in the bounds, and the caret rect (sized from the same line box) shrinks to match. Other paragraph-style fields (alignment, indent) are preserved so nested <Text> styling survives. The shadow node measures from state, so undo the strip in _updateState before pushing — restore stripped line heights from defaultTextAttributes so the cell height stays at the configured lineHeight across edits. Placeholder on both UITextField.attributedPlaceholder (UILabel draw) and RCTUITextView._placeholderView — both honor NSBaselineOffsetAttributeName. Add the offset computation to _placeholderTextAttributes on both backing views so the placeholder is centered to match (single string, single set of attributes — a direct computation is equivalent to RCTApplyBaselineOffset). Bug only manifests on Fabric. Paper has had a similar baseline-offset fix in RCTUITextView.attributedText since 0.66 (see RCTUITextView setAttributedText:), which never made it into the Fabric component view.
156b724 to
3fbf76f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On iOS, when a
TextInputhaslineHeight > fontSize, UIKit anchors typed text and the placeholder to the bottom of the paragraph line box, and sizes the single-line caret to the full line-box height instead of the font height.fontSize: 16, lineHeight: 80. iOS 26 simulator, Fabric.Why
The fix splits two ways because UIKit's draw paths don't all honor the same attributes:
NSBaselineOffsetAttributeName?UITextView)UILabel)UITextField/UIFieldEditor)RCTApplyBaselineOffsethelper that<Text>already uses, so per-fragment fonts (nested<Text>with differentfontSize) are handled correctly.paragraphStyle.minimumLineHeight/maximumLineHeightper range on the attributed string handed to UIKit. UITextField then renders at the font's natural line height and its built-in vertical centering positions the glyph in the bounds; the caret rect — derived from the same line box — shrinks to match. OtherparagraphStylefields (alignment, indent) are preserved per range. The shadow node measures fromTextInputState, so_updateStatere-inflates stripped line heights fromdefaultTextAttributesbefore pushing — without that step the cell would shrink to the font's natural height after the first keystroke.The typed-text fix lives in
RCTTextInputComponentView._setAttributedString:(single Fabric entry point, preserves the_textOf:equals:early-return). The placeholder fix lives in_placeholderTextAttributesof each backing view.Performance
When
lineHeight ≤ font.lineHeight(common case): zero allocations — guarded out before any mutation.Changelog:
[IOS] [FIXED] - Center typed TextInput text, placeholder, and single-line caret when
lineHeight > fontSize.Test Plan
RN Tester → TextInput → lineHeight baseline. Verified on iOS 26 simulator (iPhone 16 Pro / iPhone 17 Pro Max) on Fabric, including nested
<Text>mixed-font cases. Confirmed cell height stays stable across edits.Related: #38359, #39145, #53092.