Skip to content

Long text inputs within ScrollView #937

Open
@TimurKr

Description

@TimurKr

Hi, first of all, this seems like a great library, good job!

I'm quite new to react native but can already tell that getting th keyboard behaviour right is a major painpoint. I am building a simple notes app, almost an apple notes clone. No fancy rich text editing, just a couple simple multiline textinputs in a scroll view and a toolbar that should be sticky above the keyboard I tried using all of the hooks and components this library provides, but to no avail. I'll list my requirements, approaches I've tried, and share why they failed. This way you might point me in the directoin of a solution, you might notice some bugs in the library itself, and it might be a helpfull reference for other newcomers to this repo.

Requirements:

  • A basic note taking page (think apple notes, but without rich text editing features)
  • The view consists of:
    • Header
    • A scrollview with multiple components, this is where the textinputs are, but there might be other components, such as images, etc.
    • A toolbar that is sticky above the keyboard, it needs to be animated along with the keyboard
  1. The keyboard can be interactively dismissed (just like keyboardDismissMode="interactive"), but the dismissal start at the top of the toolbar, not the keyboard itself
  2. The toolbar is animated along the keyboard, not simply jumping between open and closed state
  3. When the keayboard is expanded, it does not obstruct the scrollview, so it is possible to scroll to the bottom
  4. Focusing a text input scrolls the view so that the caret "comfortably" within view (this means it is not obstructed by the keyboard, the toolbar, nor the header and has a safe padding, eg. 50 px from the header/toolbar)
  5. As the user types and the caret changes vertical position, the view should be scrolled so that the caret is within the "comfortable" boundaries, but only if it gets out of them.
  6. Lifting the finger after scrolling the view should not focus the text input the scrll happened over

All of the features above are directly taken from the behavior of the Apple notes app.

Tried solution

1. KeyboardGestureArea

I tried using the KeyboardGestureArea to dismiss the keyboard with an offset, but that only works if the currentyl focused input has a nativeID set to the same value as the textInputNativeID on the KeyboardGestureArea. As I have multiple text inputs, if I set the same nativeID for all of them, removing the focus from the currently focused input closes the keyboard. As if there was a listener on the blur event of the input with the same nativeID that closes the keyboard. I basically gave up on this and just accepted the closing starts on the top of the keyboard and not the toolbar.

2. KeyboardAvoidingView

I tried using KeyboardAvoidingView with a ScrollView, but just couldn't get it to work. Just too many issues and seems like to be the wrong approach anyway.

3. KeyboardAwareScrollView

I tried using KeyboardAwareScrollView, this got me very close, setting both bottomOffset and extraKeyboardSpace to the toolbar size, works nicely. Some issues are still present though:

  1. If the textinput is larger than the visible part, the scrolling starts to fail. Especially as you write at the end of the textinput and new lines are appended, the scroll jumps to the top of the textinput and then scrolls back down on each new line, making it basically unusable for longer textinputs.
  2. Releasing a tap after scrolling focuses the text input under the finger
  3. I couldn't find a solution to make the "comfortably" boundary for the caret to be placed in. The scroll is often unpredictably with long textinputs.

4. Custom solution using useReanimatedKeyboardAnimation, useFocusedInputHandler, and useReanimatedFocusedInput

see https://github.com/TimurKr/KeyboardControllerExample for a simple expo example

Finally I tried building my own solution, (see components/CustomKeyboardAwareScrollView.tsx). This got me the closest to the desired behaviour, but there are still some issues:

  1. If the textinput is larger than the visible part, the scrolling starts to fail. Especially as you write at the end of the textinput and new lines are appended, the scroll jumps to the top of the textinput and then scrolls back down on each new line, making it basically unusable for longer textinputs. No idea where this scrolling to the top is coming from...
  2. Focusing on the textinput in a place that get immedatelly obstructed by the keaboard does not trigger the custom scrolling behavior, so the "comfortably" boundary is not respected. Instead the default scrolling happens so the caret is just barely in the scrollview. (This is caused by the measure function returning the height of the scrollview before the keyboard is shown, so the calculations assumes the keyboard is hidden, so no scrolling happens)
  3. Releasing a tap after scrolling focuses the text input under the finger

Related issues

I see this PR #901 solving this issue #897 is attempting to fix the long textinput and scrolling issues. I haven't tried the changes in it and see there are multiple comments suggesting changes before merge.

Sorry for the long comment, but it seems like this repo did most of the hard work around handling keyboards in RN, but the last 10% is missing. I spent over 10 hours on this issue and I still couldn't figure it out. If the functionality is there, perhaps the docs need improvement. Thanks for you hard work, if there is anything I could help with, let me know. Thanks for any tips on how to get this working!

Setup I was testing on:

  • Desktop OS: MacOS 15.3.2
  • Device: iPhone16
  • OS: iOS 18.0
  • RN version: 0.79.2
  • RN architecture: new
  • Library version: 1.17.1

Metadata

Metadata

Assignees

Labels

KeyboardAwareScrollView 📜Anything related to KeyboardAwareScrollView component🐛 bugSomething isn't working👆 interactive keyboardAnything related to interactive keyboard dismissing

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions