From e6a844dc1c54d28a54be6cfeb74cd5b89435ecca Mon Sep 17 00:00:00 2001 From: Ido Yana Date: Tue, 7 Jul 2026 21:31:33 +0300 Subject: [PATCH] fix: show soft keyboard when long-press starts text selection in TextInput on Android MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ReactEditText marks itself textIsSelectable in onAttachedToWindow (a removeClippedSubviews workaround, #6805), which makes the platform Editor treat every RN TextInput as read-only selectable text and skip its "Show the IME to be able to replace text" branch when a selection action mode starts (Editor#startActionModeInternal gates that branch on !isTextSelectable()). RN's own keyboard paths only cover clicks and programmatic focus, so long-pressing to select text in an unfocused input — or in a focused input after the keyboard was dismissed — left the user with a selection toolbar and no keyboard. Compensate in ReactEditText: request the keyboard when a selection or insertion action mode is created, and when focus is gained with a non-collapsed selection (the action mode can precede focus). Guarded by isEnabled (the editable prop), isInTouchMode, and showSoftInputOnFocus, mirroring both requestFocusProgrammatically() and the platform branch. Co-Authored-By: Claude Fable 5 --- .../react/views/textinput/ReactEditText.kt | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt index 0415dca1126..c967b1c29bc 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt @@ -258,6 +258,13 @@ public open class ReactEditText public constructor(context: Context) : AppCompat if (contextMenuHidden) { return false } + // setTextIsSelectable(true) (see onAttachedToWindow) makes the platform Editor + // treat this view as read-only selectable text and skip its "Show the IME to be + // able to replace text" branch when a selection or insertion action mode starts + // (Editor#startActionModeInternal gates it on !isTextSelectable()). Compensate + // here so long-pressing an editable input summons the keyboard, matching stock + // EditText behavior. + showSoftKeyboardIfEditable() menu.removeItem(android.R.id.pasteAsPlainText) return true } @@ -499,6 +506,14 @@ public open class ReactEditText public constructor(context: Context) : AppCompat if (focused && selectionWatcher != null) { selectionWatcher?.onSelectionChanged(selectionStart, selectionEnd) } + // Gaining focus with a non-collapsed selection means focus arrived through a + // long-press text selection rather than a tap or programmatic focus — the one focus + // path that never requests the soft keyboard (see onCreateActionMode). The action + // mode can be created before this view becomes the IME-served view, so request the + // keyboard again now that focus has landed. + if (focused && hasSelection()) { + showSoftKeyboardIfEditable() + } } internal fun setSelectionWatcher(selectionWatcher: SelectionWatcher?) { @@ -909,6 +924,14 @@ public open class ReactEditText public constructor(context: Context) : AppCompat protected fun showSoftKeyboard(): Boolean = inputMethodManager.showSoftInput(this, 0) + // Mirrors the guard on requestFocusProgrammatically(), plus editability ("editable" + // prop maps to isEnabled): never summon the keyboard for a read-only input. + private fun showSoftKeyboardIfEditable() { + if (isEnabled && isInTouchMode && showSoftInputOnFocus) { + showSoftKeyboard() + } + } + protected fun hideSoftKeyboard() { inputMethodManager.hideSoftInputFromWindow(windowToken, 0) }