From 117eb57e887a4853b118dcaf2f6a448b3117a227 Mon Sep 17 00:00:00 2001 From: amerllica Date: Sat, 24 Oct 2026 12:04:53 +0330 Subject: [PATCH 1/3] Fix TextInput onContentSizeChange not firing on text change on iOS --- .../TextInput/RCTTextInputComponentView.mm | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index 281c5ea88b53..15a045ff266c 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -395,10 +395,7 @@ - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics _backedTextInputView.textContainerInset = RCTUIEdgeInsetsFromEdgeInsets(layoutMetrics.contentInsets - layoutMetrics.borderWidth); - if (!CGSizeEqualToSize(_previousContentSize, _backedTextInputView.contentSize) && _eventEmitter) { - _previousContentSize = _backedTextInputView.contentSize; - static_cast(*_eventEmitter).onContentSizeChange([self _textInputMetrics]); - } + [self _emitContentSizeChangeIfNeeded]; } - (void)prepareForRecycle @@ -415,6 +412,7 @@ - (void)prepareForRecycle _backedTextInputView.inputAccessoryViewID = nil; _backedTextInputView.inputAccessoryView = nil; _hasInputAccessoryView = false; + _previousContentSize = CGSizeZero; [_backedTextInputView resignFirstResponder]; } @@ -565,6 +563,8 @@ - (void)textInputDidChange const auto &textInputEventEmitter = static_cast(*_eventEmitter); textInputEventEmitter.onChange([self _textInputMetrics]); } + + [self _emitContentSizeChangeAfterTextChange]; } - (void)textInputDidChangeSelection @@ -803,6 +803,22 @@ - (void)handleInputAccessoryDoneButton }; } +- (void)_emitContentSizeChangeAfterTextChange +{ + [_backedTextInputView layoutIfNeeded]; + [self _emitContentSizeChangeIfNeeded]; +} + +- (void)_emitContentSizeChangeIfNeeded +{ + CGSize contentSize = _backedTextInputView.contentSize; + if (CGSizeEqualToSize(_previousContentSize, contentSize) || !_eventEmitter) { + return; + } + _previousContentSize = contentSize; + static_cast(*_eventEmitter).onContentSizeChange([self _textInputMetrics]); +} + - (void)_updateState { if (!_state) { @@ -881,6 +897,7 @@ - (void)_setAttributedString:(NSAttributedString *)attributedString [self _restoreTextSelectionAndIgnoreCaretChange:YES]; [self _updateTypingAttributes]; _lastStringStateWasUpdatedWith = attributedString; + [self _emitContentSizeChangeAfterTextChange]; } // Ensure that newly typed text will inherit any custom attributes. We follow the logic of RN Android, where attributes From 8317f8cd70d3f6037a14e93df245cdb4ceca4cef Mon Sep 17 00:00:00 2001 From: amerllica Date: Sat, 24 Oct 2026 12:04:54 +0330 Subject: [PATCH 2/3] Add fixed height content size TextInput example to RNTester --- .../examples/TextInput/TextInputSharedExamples.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js index 795ea66911ea..75448f58a599 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js @@ -1192,6 +1192,19 @@ module.exports = [ ); }, }, + { + title: 'Content size change with fixed height', + name: 'contentSizeChangeFixedHeight', + render: function (): React.Node { + return ( + + + + ); + }, + }, { title: 'Drag and drop', render: function (): React.Node { From c6617ef5c0e2a3ad1f8b1ffbffd6d0f0a7a0da09 Mon Sep 17 00:00:00 2001 From: amerllica Date: Sat, 24 Oct 2026 12:29:26 +0330 Subject: [PATCH 3/3] Skip TextInput content size event from text changes before first layout on iOS --- .../ComponentViews/TextInput/RCTTextInputComponentView.mm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index 15a045ff266c..9f523c63bbeb 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -805,10 +805,18 @@ - (void)handleInputAccessoryDoneButton - (void)_emitContentSizeChangeAfterTextChange { + if (![self _hasEmittedContentSize]) { + return; + } [_backedTextInputView layoutIfNeeded]; [self _emitContentSizeChangeIfNeeded]; } +- (BOOL)_hasEmittedContentSize +{ + return !CGSizeEqualToSize(_previousContentSize, CGSizeZero); +} + - (void)_emitContentSizeChangeIfNeeded { CGSize contentSize = _backedTextInputView.contentSize;