Skip to content

Fix KeyboardAvoidingView behavior for multi-line TextInputs on iOS - #58436

Open
jasozh wants to merge 4 commits into
react:mainfrom
jasozh:export-D119204440
Open

Fix KeyboardAvoidingView behavior for multi-line TextInputs on iOS#58436
jasozh wants to merge 4 commits into
react:mainfrom
jasozh:export-D119204440

Conversation

@jasozh

@jasozh jasozh commented Sep 10, 2026

Copy link
Copy Markdown

Summary:
Fixes the issue described in #16826, where KeyboardAvoidingView does not reveal multi-line TextInputs when used with an enclosing ScrollView on iOS.

Root Cause

When a text input is focused on iOS, UIKit reveals the input by applying a scroll operation on the innermost ScrollView. When a single-line UITextField is inside a ScrollView, this scrolls the ScrollView itself, revealing the input correctly.

However, the multi-line UITextView itself extends UIScrollView. When a UITextView is inside a ScrollView, UIKit applies the scroll operation only on the input and not the surrounding ScrollView. If the input is in a position where it is covered by the keyboard, it will remain covered afterwards.

Community members have found a workaround by setting scrollEnabled={false} on multi-line inputs. This disables scrolling on the UITextView, so the scroll operation is correctly applied on the surrounding ScrollView. However, this workaround comes with obvious downsides, and solutions offered by third-party libraries are often used instead.

This PR

Modify RCTUITextView to override the scrollRectToVisible(_:animated:) method which is what UIKit uses to implicitly reveal the text view. The scrolling operation is performed on the text view like before, but we then forward the same operation to the nearest scrollable ancestor (such as a surrounding ScrollView). This ensures that the text view itself is always scrolled into view as scrolling is always applied to the parent.

Limitations

The main limitation is that we rely on UIKit to reveal the text input, since KeyboardAvoidingView itself implements no scrolling logic. This also leads to some discrepancy in behavior with Android. On Android, the entire text box is revealed on focus, whereas on iOS with this fix, only the caret line is revealed.

We can introduce additional logic in RCTUITextView to reveal the entire text view, but this won't apply to text views with scrollEnabled={false} which will still only reveal the caret line using UIKit's default behavior.

Native approaches on iOS generally involve manually handling the keyboard avoiding behavior by adding keyboard event listeners and manually triggering scrollView.scrollRectToVisible() when receiving the keyboardDidShow() notification. We can do something similar in RCTScrollViewComponentView, but this explicitly violates the contract there which prohibits behavior that contradicts a standard UIScrollView.

In contrast, this approach aligns with what is already being used to reveal both UITextField and UITextView with scrollEnabled={false}.

Changelog: [iOS][Fixed] Reveal multi-line text inputs when using KeyboardAvoidingView with a ScrollView

Differential Revision: D119204440

Summary:

In the RNTester KeyboardAvoidingView example, fix minor spacing issues and add descriptions for "Keyboard Avoiding View with enabled={false}" and "Keyboard Avoiding View with contentContainerStyle".

Changelog:
[Internal]

Differential Revision: D119204437
Summary:

The RNTester KeyboardAvoidingView example had alignment issues with the close button on top of the example form. When KeyboardAvoidingView's behavior was toggled to "position", a small amount of right padding is added to the close button, making it appear non-flush with the right edge of the form. This impacted both the "Keyboard Avoiding View with different behaviors" screen and the "Keyboard Avoiding View with contentContainerStyle" screen.

Changelog:
[Internal]

Differential Revision: D119204438
Summary:

Add a new RNTester example in KeyboardAvoidingView for using the component with a ScrollView. This reproduces the issue raised in [react#16826](react#16826) where keyboard avoiding behavior fails for multi-line text fields in a ScrollView on iOS. As this is a common use case, the example acts as a reference to show intended behavior and prevent future regressions.

Changelog:
[Internal]

Differential Revision: D119204439
Summary:
Fixes the issue described in [react#16826](react#16826), where KeyboardAvoidingView does not reveal multi-line TextInputs when used with an enclosing ScrollView on iOS.

### Root Cause

When a text input is focused on iOS, UIKit reveals the input by applying a scroll operation on the innermost ScrollView. When a single-line UITextField is inside a ScrollView, this scrolls the ScrollView itself, revealing the input correctly.

However, the multi-line UITextView itself extends UIScrollView. When a UITextView is inside a ScrollView, UIKit applies the scroll operation only on the input and not the surrounding ScrollView. If the input is in a position where it is covered by the keyboard, it will remain covered afterwards.

Community members have found a workaround by setting `scrollEnabled={false}` on multi-line inputs. This disables scrolling on the UITextView, so the scroll operation is correctly applied on the surrounding ScrollView. However, this workaround comes with obvious downsides, and solutions offered by third-party libraries are often used instead.

### This PR

Modify RCTUITextView to override the `scrollRectToVisible(_:animated:)` method which is what UIKit uses to implicitly reveal the text view. The scrolling operation is performed on the text view like before, but we then forward the same operation to the nearest scrollable ancestor (such as a surrounding ScrollView). This ensures that the text view itself is always scrolled into view as scrolling is always applied to the parent.

### Limitations

The main limitation is that we rely on UIKit to reveal the text input, since KeyboardAvoidingView itself implements no scrolling logic. This also leads to some discrepancy in behavior with Android. On Android, the entire text box is revealed on focus, whereas on iOS with this fix, only the caret line is revealed.

We can introduce additional logic in RCTUITextView to reveal the entire text view, but this won't apply to text views with `scrollEnabled={false}` which will still only reveal the caret line using UIKit's default behavior.

Native approaches on iOS generally involve manually handling the keyboard avoiding behavior by adding keyboard event listeners and manually triggering `scrollView.scrollRectToVisible()` when receiving the `keyboardDidShow()` notification. We can do something similar in `RCTScrollViewComponentView`, but this explicitly violates the contract there which prohibits behavior that contradicts a standard UIScrollView.

In contrast, this approach aligns with what is already being used to reveal both UITextField and UITextView with `scrollEnabled={false}`.

Changelog: [iOS][Fixed] Reveal multi-line text inputs when using KeyboardAvoidingView with a ScrollView

Differential Revision: D119204440
@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 Sep 10, 2026
@meta-codesync

meta-codesync Bot commented Sep 10, 2026

Copy link
Copy Markdown

@jasozh has exported this pull request. If you are a Meta employee, you can view the originating Diff in D119204440.

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. meta-exported p: Facebook Partner: Facebook Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant