Skip to content

[Android] Long-pressing a TextInput that is unfocused (or focused with the keyboard dismissed) starts text selection but never shows the soft keyboard #57470

Description

@idoyana

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:

  1. The input is unfocused and the first gesture is a long-press.
  2. 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

  1. Render the snippet below (multiline TextInput with some text) — or open RNTester → TextInput → "Default color text".
  2. Without tapping the field first, long-press a word inside it.
  3. Observe: word selected + selection toolbar, field focused (onFocus fires) — no keyboard.
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs: AttentionIssues where the author has responded to feedback.Needs: ReproThis issue could be improved with a clear list of steps to reproduce the issue.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions