feat: custom keyboard support - #1548
Open
VladyslavMartynov10 wants to merge 1 commit into
Open
Conversation
kirillzyusko
self-requested a review
July 15, 2026 14:04
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.
📜 Description
Adds a new
CustomKeyboardcomponent that replaces the system keyboard with arbitrary JSX whenever a text input is focused (iOS viainputView, Android via a bottom-anchoredWindowManagerpanel with IME suppression). The keyboard content is regular React — it lives in the component tree, handles touches, and defines its own height.💡 Motivation and Context
There was no maintained way to render a fully custom keyboard in RN — the library could extend (
KeyboardExtender), overlay (OverKeyboardView), or mimic (KeyboardBackgroundView) the keyboard, but not replace it. The only prior art (Wixreact-native-keyboard-input) is legacy-bridge and unmaintained. Unlike that approach, presenting inside the real keyboard window (iOS) / emitting synthetic keyboard events (Android) keeps the whole avoidance ecosystem working for free.📢 Changelog
JS
CustomKeyboardcomponent (enabledprop, iOS + Android; web renders nothing)CustomKeyboardViewcodegen spec, types, and exportsCustomKeyboardexample screen (emoji keyboard +KeyboardAwareScrollViewmulti-input form)iOS
CustomKeyboardViewManager— attaches a sharedUIInputView(.keyboard)to the focused input'sinputView, with weak attach tracking and cleanup on focus change / unmount / window removal / recycleadopt()+ state push from the view; PaperCustomKeyboardShadowView)Android
CustomKeyboardHostView/CustomKeyboardRootViewGroup—WindowManagerpanel (bottom gravity, non-focusable), IME suppression with focus preserved, per-IME background color, 250ms slide animationsKeyboardAnimationCallback.animateSyntheticTransition()— animated synthetic keyboard events (will/did + per-frame Move) with cancellation handling; real IME events suspended while the panel owns the keyboard; instant focus-change events gated byisSuspendedCustomKeyboardViewManager, package registration,RNKC.hdescriptor, and shadow-node-driven width (StateWrapperpush /CustomKeyboardHostShadowNode)🤔 How Has This Been Tested?
Manually on iPhone 17 / 17 Pro simulators (iOS 26.2) and Pixel 9a emulator (API 36), old architecture (new-arch Kotlin/C++ compile-checked): custom keyboard presents on focus and inserts into the focused field across 10 inputs; live switching to/from the system keyboard;
KeyboardAwareScrollView/KeyboardAvoidingViewavoidance driven by the custom keyboard height; clean show/hide animations (Android hide verified frame-by-frame via screen recording — no flashes); navigation away restores the system keyboard; rapid focus/dismiss races.📸 Screenshots (if appropriate):
iOS.mov
Android.mov
📝 Checklist
TODO
@kirillzyusko Can you check the Android part?