react-native-keyboard-controller

Activity, over time

Daily observations from the public event archive.

Attention

Daily stars & forks

Loading attention chart

Star accumulation

Cumulative stars

Loading star accumulation chart

Pull requests

Daily opens & merges

Loading pull requests chart

Conversations

Daily issues & comments

Loading conversations chart

Community

Daily accounts & reviews

Loading community chart

Releases

Daily releases

Loading releases chart

Mentions

2posts · 30d
Nov 40 posts
  1. DEV · · @zaynsaul

    Keyboard-aware forms in React Native and Expo, with a Save button that rides the keyboard Every React Native app with a form hits the same wall. You tap a field low on the screen, the keyboard opens, and the field is gone behind it. The Save button too. The usual fixes get you most of the way. KeyboardAvoidingView behaves differently on iOS and Android. KeyboardAwareScrollView from react-native-keyboard-controller is much better, and it's what I build on. But once a real form screen has a footer button, a previous / next toolbar, a modal sheet or a validation error, the edge cases start piling up. I hit all of them while building a booking app, so I pulled the fix out into a small package: @saulzayn/rn-keyboard-form. This post shows the problems, what was behind each one, and how to use it. !The same form without the package (the keyboard covers the field and Save) and with it What a form screen needs - The focused field scrolls above the keyboard, and above anything sitting on the keyboard. - A footer (Save, Continue, Send) stays at the bottom and rides on top of the keyboard while it's open, so you never have to close the keyboard to submit. - A toolbar on the keyboard with ↑ / ↓ / Done to move between fields. - The same thing inside an iOS modal sheet, an iPad form sheet and a bottom sheet. - Phones and tablets, portrait and landscape, and turning the device with the keyboard open. Each of these is easy alone. Together they fight each other. The problems I ran into 1. The footer hides the field you're typing in. If the Save button rides on the keyboard, the scroll view has to know the footer is there too, or it scrolls the field to just above the keyboard, right behind the button. So the footer's height has to be added to the scroll offset. And when the footer changes size (an error banner appears in it), that offset changes as well. 2. Changing that offset at the wrong moment scrolls twice. Inside an Android Modal, the footer's safe-area padding changes while it rides up with the keyboard. Updating the scroll offset during the animation made the field jump up twice. The fix was to hold the offset while the keyboard is opening or closing, and apply changes only once it has settled. 3. Safe-area insets lie inside an iOS modal sheet. useSafeAreaInsets() still reports the home-bar inset inside a page sheet, where the real bottom inset is 0. The package measures it with a hidden SafeAreaView instead, so the footer doesn't get a gap under it. 4. iPad sheets only move part of the way. In an iPad form or page sheet, iOS lifts the sheet only part of the way when the keyboard opens. So "the keyboard is 300pt tall" isn't how much of your form it covers. The footer and toolbar are moved by the overlap: how far the keyboard actually reaches into the form, measured in window coordinates. 5. The rounded keyboard on iOS 26+. The new keyboard has rounded top corners, and your form shows through around them. The toolbar has to lift a little, and a strip behind it has to reach under the corners. 6. Content that changes under the focused field. An error appears above the field you're in, or a switch adds three more fields. The field moves, but nothing scrolls. The package re-measures the focused field when the content size changes and scrolls the rest of the way. 7. Jumping. A Reddit commenter spotted this one in my demo video: moving to the next field while an error and a footer banner appeared caused three scrolls in under a second. Now layout changes are checked within one or two frames and corrected without animation, so it reads as one scroll. 8. Bottom sheets. A sheet that lifts itself above the keyboard plus a KeyboardAwareScrollView inside it scrolled twice, once for each. Sheets get their own component that only scrolls the focused field into view once the sheet has moved. On Android a sheet is also its own window, so ↓ on the toolbar jumped to a field behind the sheet until each form's fields were grouped. Using it Install it next to its peers (with Expo, use npx expo install for the last three): yarn add @saulzayn/rn-keyboard-form react-native-keyboard-controller react-native-reanimated react-native-safe-area-context keyboard-controller is a native module, so you need a development build, not Expo Go. Wrap the app once With Expo Router, in the root app/_layout.tsx: import { Stack } from 'expo-router'; import { SafeAreaProvider } from 'react-native-safe-area-context'; import { KeyboardHost } from '@saulzayn/rn-keyboard-form'; export default function RootLayout() { return ( <SafeAreaProvider> <KeyboardHost> <Stack /> </KeyboardHost> </SafeAreaProvider> ); } A form screen with a Save button import { Button, TextInput } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { FormScroll } from '@saulzayn/rn-keyboard-form'; export default function EditProfile() { return ( <FormScroll footer={ <SafeAreaView edges={['bottom']} style={{ padding: 16, backgroundColor: 'white' }}> <Button title="Save" onPress={save} /> </SafeAreaView> } > <TextInput placeholder="Name" /> <TextInput placeholder="Email" keyboardType="email-address" /> <TextInput placeholder="Bio" multiline /> </FormScroll> ); } That's it: the focused field stays above the keyboard and the Save button, Save rides on the keyboard, and the ↑ / ↓ / Done toolbar is on by default (toolbar={false} turns it off). A bottom sheet Your sheet moves itself above the keyboard; SheetScroll scrolls the focused field into view inside it and keeps the footer in sight: <SheetScroll contentContainerStyle={{ padding: 16, gap: 12 }} footer={<Button title="Send" onPress={send} />} > <TextInput placeholder="Name" /> <TextInput placeholder="Message" multiline /> </SheetScroll> Forms in steps Give FormScroll (or SheetScroll) a key per step and focus the next step's first field, and the keyboard stays up between steps on iOS. On Android, removing the focused field always closes the keyboard, so the example app waits for it to close and then opens it on the next field. The README has the details. Theming Light and dark themes are built in, and you can change the toolbar colours, the Done label, spacing and the gap above the focused field: <KeyboardHost theme={mergeTheme(darkTheme, { toolbar: { tint: '#E5484D', doneLabel: 'OK' } })}> How it was tested Every screen in the example app on a Pixel 7 Pro, an iPhone with the iOS 26+ rounded keyboard, iPad and Android tablet, in portrait and landscape, turning the device with the keyboard open, in light and dark mode. It works with keyboard-controller 1.21.6 and newer (Expo SDK 56, 57 and 58). Two things are still on my list: a multiline field low on the screen first scrolls only to its caret (that's keyboard-controller's behaviour), and right after switching an Android app between full screen and a floating window, the first keyboard open can be off. Try it - npm: @saulzayn/rn-keyboard-form - GitHub, with the example app: ZaynSaul/rn-keyboard-form All the heavy lifting is done by react-native-keyboard-controller; this package is the form-screen layer on top. If your form breaks on a device or layout I haven't covered, please open an issue with a screen recording, and I'll fix it.

  2. @dom000_dev RN uses native components, but its architecture doesn't allow for perfectly native behaviour in every case. The keyboard is a good example: github.com/kirillzyusko/react-native-keyboard-con…. There're a few other known areas too. github.com/DartNative/dartnative/blob/main/docs/a…

    1 like · 17 views

Latest stargazers

The last 10 distinct accounts we observed this year.

Most active participants

PR, issue, comment & review events in the past year.

Packages

2
PackageVersionDownloads · 30dTrend · 30d
e2e-testsv1.5.0
v1.5.0
≥84
v1.9.5
≥7.8M

README badges

Embed a badge in your README or website.

Live mentions · last 30 days
kirillzyusko/react-native-keyboard-controller mentions in the last 30 days