Reproducer
Snack (Android): https://snack.expo.dev?platform=android&name=RN%20%2357470%20long-press%20keyboard%20repro&sourceUrl=https%3A%2F%2Fgist.githubusercontent.com%2Fidoyana%2Fd4a7978d541174df974a9de08838ab8a%2Fraw%2FApp.js
(source gist: https://gist.github.com/idoyana/d4a7978d541174df974a9de08838ab8a — the bug involves real long-press gestures + the device soft keyboard, so run it on a physical Android device / Expo Go, not the web preview)
Steps: run on an Android device → without tapping first, long-press a word in either input → word is selected + Cut/Copy toolbar, but no keyboard. Also reproducible after tap → dismiss keyboard (back) → long-press.
Description
On Android, long-pressing text inside a TextInput while the soft keyboard is hidden puts the field into text-selection mode (selection highlight + Cut/Copy/Paste toolbar) and the field gains focus — but showSoftInput is never requested, so the keyboard never appears. The user is left with a selection toolbar and no way to type; the only way to remove text is "Cut". Reproduced on multiline inputs (long and short content) and on single-line inputs.
This happens in two states:
- The input is unfocused and the first gesture is a long-press.
- The input is focused but the keyboard was dismissed (back gesture), then the user long-presses.
A plain tap works correctly in both states (keyboard shows). Once the keyboard is visible, long-press selection also behaves correctly. Reproduced with a bare react-native TextInput inside a plain View — no third-party components, no ScrollView.
This matters in practice: users habitually long-press a word to start editing (e.g. to replace it), and end up stuck with a selection and no keyboard.
Steps to reproduce
- Render the snippet below (multiline
TextInput with some text) — or open RNTester → TextInput → "Default color text".
- Without tapping the field first, long-press a word inside it.
- Observe: word selected + selection toolbar, field focused (
onFocus fires) — no keyboard.
- Also: tap the field (keyboard shows), dismiss the keyboard with the back gesture, then long-press → same bug.
import { useState } from "react";
import { StyleSheet, Text, TextInput, View } from "react-native";
const LONG =
"Some recipe text for testing\n" +
Array.from({ length: 22 }, (_, i) => `line ${i + 1}: a bit of text`).join("\n");
export default function Repro() {
const [val, setVal] = useState(LONG);
return (
<View style={styles.container}>
<Text>Long-press a word below while the keyboard is hidden:</Text>
<TextInput
multiline
value={val}
onChangeText={setVal}
style={styles.input}
textAlignVertical="top"
/>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 16, gap: 8, backgroundColor: "#fff" },
input: { borderWidth: 1, borderRadius: 8, padding: 10, minHeight: 140, fontSize: 15 },
});
Expected
Long-press should behave like the platform default for Android EditText: start selection and show the soft keyboard, so the selected text can be replaced by typing.
Actual
Selection starts, focus is gained, keyboard never appears.
Evidence (adb IME trace)
Tap on the field — normal path, keyboard requested and shown:
ImeTracker: onRequestShow at ORIGIN_CLIENT reason SHOW_SOFT_INPUT fromUser true
GoogleInputMethodService: onStartInput(... inputType=Normal[MultiLine|CapSentences], initialSelStart=94, initialSelEnd=94 ...)
ImeTracker: onShown
Long-press on the same field while keyboard hidden — input connection starts with a selection range, but no show request is ever issued:
GoogleInputMethodService: onStartInput(... inputType=Normal[MultiLine|CapSentences], initialSelStart=79, initialSelEnd=84 ...)
(no ImeTracker onRequestShow / onShown for the app)
dumpsys input_method: mServedView=com.facebook.react.views.textinput.ReactEditText ... mInputShown=false
On RNTester (main, 0015d1e4f9), the same long-press produces selection + toolbar with zero ImeTracker events and mInputShown=false.
JS-side, onFocus does fire on the long-press, and calling .focus() from it is a no-op (the field is already focused), so there is no clean JS-level recovery.
Root cause
Stock Android does show the IME when a selection action mode starts on editable text — Editor#startActionModeInternal():
final boolean selectionStarted = mTextActionMode != null;
if (selectionStarted
&& mTextView.isTextEditable() && !mTextView.isTextSelectable()
&& mShowSoftInputOnFocus) {
// Show the IME to be able to replace text, except when selecting non editable text.
final InputMethodManager imm = getInputMethodManager();
if (imm != null) {
imm.showSoftInput(mTextView, 0, null);
}
}
But ReactEditText.onAttachedToWindow() calls super.setTextIsSelectable(true) (a workaround for text selection inside removeClippedSubviews, #6805). That makes isTextSelectable() return true, so the platform's branch above classifies every RN TextInput as read-only selectable text and deliberately skips the keyboard.
RN's own keyboard-showing paths don't cover it either — the comment on requestFocusProgrammatically() documents that only clicks and programmatic focus pop the keyboard. Long-press selection is a third focus path that neither covers.
Suggested fix: compensate in ReactEditText — request the keyboard when a selection/insertion action mode starts (and on focus gained with a non-collapsed selection), mirroring the platform branch its setTextIsSelectable(true) opted out of. PR incoming.
Environment
- Reproduced on main (commit
0015d1e4f9) with RNTester — TextInput example, "Default color text" field: long-press with keyboard hidden → word selected + Cut/Copy toolbar, mInputShown=false, and zero ImeTracker show requests in logcat
- Also reproduced on react-native 0.85.3 (New Architecture, Expo SDK 56 dev client) with a bare
TextInput in a plain View (and through react-native-paper — not paper-specific)
- Device: Google Pixel 10 Pro, Android 16 (SDK 36), Gboard
Related but distinct: #30746 / #19366 (re-focus doesn't reopen keyboard), #33697 (selection toolbar quirks).
Workaround (app level)
A long-press always produces a non-empty selection, so on onSelectionChange, if start !== end && !Keyboard.isVisible(), dispatch the native focus command directly at the already-focused field — Commands.focus(TextInputState.currentlyFocusedInput()) (from react-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent) — which reaches requestFocusFromJS() → showSoftKeyboard() even though focus doesn't change. Collapsed selections (taps/typing) are ignored so the native tap path is untouched.
Reproducer
Snack (Android): https://snack.expo.dev?platform=android&name=RN%20%2357470%20long-press%20keyboard%20repro&sourceUrl=https%3A%2F%2Fgist.githubusercontent.com%2Fidoyana%2Fd4a7978d541174df974a9de08838ab8a%2Fraw%2FApp.js
(source gist: https://gist.github.com/idoyana/d4a7978d541174df974a9de08838ab8a — the bug involves real long-press gestures + the device soft keyboard, so run it on a physical Android device / Expo Go, not the web preview)
Steps: run on an Android device → without tapping first, long-press a word in either input → word is selected + Cut/Copy toolbar, but no keyboard. Also reproducible after tap → dismiss keyboard (back) → long-press.
Description
On Android, long-pressing text inside a
TextInputwhile the soft keyboard is hidden puts the field into text-selection mode (selection highlight + Cut/Copy/Paste toolbar) and the field gains focus — butshowSoftInputis never requested, so the keyboard never appears. The user is left with a selection toolbar and no way to type; the only way to remove text is "Cut". Reproduced on multiline inputs (long and short content) and on single-line inputs.This happens in two states:
A plain tap works correctly in both states (keyboard shows). Once the keyboard is visible, long-press selection also behaves correctly. Reproduced with a bare
react-nativeTextInputinside a plainView— no third-party components, no ScrollView.This matters in practice: users habitually long-press a word to start editing (e.g. to replace it), and end up stuck with a selection and no keyboard.
Steps to reproduce
TextInputwith some text) — or open RNTester → TextInput → "Default color text".onFocusfires) — no keyboard.Expected
Long-press should behave like the platform default for Android
EditText: start selection and show the soft keyboard, so the selected text can be replaced by typing.Actual
Selection starts, focus is gained, keyboard never appears.
Evidence (adb IME trace)
Tap on the field — normal path, keyboard requested and shown:
Long-press on the same field while keyboard hidden — input connection starts with a selection range, but no show request is ever issued:
On RNTester (main,
0015d1e4f9), the same long-press produces selection + toolbar with zeroImeTrackerevents andmInputShown=false.JS-side,
onFocusdoes fire on the long-press, and calling.focus()from it is a no-op (the field is already focused), so there is no clean JS-level recovery.Root cause
Stock Android does show the IME when a selection action mode starts on editable text —
Editor#startActionModeInternal():But
ReactEditText.onAttachedToWindow()callssuper.setTextIsSelectable(true)(a workaround for text selection insideremoveClippedSubviews, #6805). That makesisTextSelectable()returntrue, so the platform's branch above classifies every RNTextInputas read-only selectable text and deliberately skips the keyboard.RN's own keyboard-showing paths don't cover it either — the comment on
requestFocusProgrammatically()documents that only clicks and programmatic focus pop the keyboard. Long-press selection is a third focus path that neither covers.Suggested fix: compensate in
ReactEditText— request the keyboard when a selection/insertion action mode starts (and on focus gained with a non-collapsed selection), mirroring the platform branch itssetTextIsSelectable(true)opted out of. PR incoming.Environment
0015d1e4f9) with RNTester — TextInput example, "Default color text" field: long-press with keyboard hidden → word selected + Cut/Copy toolbar,mInputShown=false, and zeroImeTrackershow requests in logcatTextInputin a plainView(and through react-native-paper — not paper-specific)Related but distinct: #30746 / #19366 (re-focus doesn't reopen keyboard), #33697 (selection toolbar quirks).
Workaround (app level)
A long-press always produces a non-empty selection, so on
onSelectionChange, ifstart !== end && !Keyboard.isVisible(), dispatch the native focus command directly at the already-focused field —Commands.focus(TextInputState.currentlyFocusedInput())(fromreact-native/Libraries/Components/TextInput/AndroidTextInputNativeComponent) — which reachesrequestFocusFromJS()→showSoftKeyboard()even though focus doesn't change. Collapsed selections (taps/typing) are ignored so the native tap path is untouched.