Skip to content

Keep a read-only TextInput focusable on Android - #59156

Draft
YevheniiKotyrlo wants to merge 1 commit into
react:mainfrom
YevheniiKotyrlo:fix/android-read-only-text-input-focus
Draft

YevheniiKotyrlo wants to merge 1 commit into
react:mainfrom
YevheniiKotyrlo:fix/android-read-only-text-input-focus

Conversation

@YevheniiKotyrlo

Copy link
Copy Markdown
Contributor

Summary:

On Android, editable={false} disables the EditText: ReactTextInputManager.setEditable writes the prop onto View.isEnabled. A disabled view takes no focus, so a hardware keyboard's Tab skips a read-only input, TalkBack announces it as disabled, and its text cannot be selected or copied. readOnly reaches native as editable={!readOnly}, so it is the same view. On the web a readonly input keeps its tab stop, its focus and its selection and refuses only edits.

This refuses input the way TextView does instead: ReactEditText drops its key listener while it is read-only. A TextView with no key listener is no text editor, so no input method serves it, hardware keys do not edit it and cut and paste leave its selection menu, while its movement method keeps it focusable and selectable. The view stays enabled, and aria-disabled / accessibilityState={{disabled: true}} still disable it through BaseViewManager.

Two TextView behaviours follow from a missing key listener:

  • getInputType() reports TYPE_NULL, so isMultiline, isSecureText and commitStagedInputType read the input type the props configured.
  • TextView marks every EditText editable for accessibility and performs ACTION_SET_TEXT whatever its key listener, so the input's accessibility delegate clears the flag, removes the action and refuses it while the input is read-only.

The soft-keyboard guard checks isEditable as well, so the paths that focus an input on their own — autoFocus, the accessibility delegate's click and a long-press selection — raise no keyboard for a read-only input. focus() keeps its contract: TextInputState.focusTextInput still refuses a non-editable input (#30695).

Related: #7437, #30597.

Changelog:

[ANDROID] [FIXED] - A TextInput with editable={false} or readOnly keeps its focus, its tab stop and its text selection

Test Plan:

  • ReactTextInputPropertyTest: on main, testEditable, testNonEditableTakesFocus and testNonEditableRefusesAccessibilitySetText fail; with this change the class passes (34 tests). New cases cover refused hardware keys, the refused ACTION_SET_TEXT, and the keyboard type, multiline and secure entry kept across a read-only window.
  • ./gradlew :packages:react-native:ReactAndroid:testDebugUnitTest -Preact.internal.useHermesStable=true passes (769 tests), and node ./scripts/format-kotlin.js --check is clean.
  • RNTester on a stock Android 16 emulator: a hardware Tab walk stops on a read-only input, and a long press selects its text with Copy offered and no Cut or Paste. The before/after recordings are in the comment below.

editable={false} disabled the EditText, so a hardware keyboard's Tab
skipped it, TalkBack announced it as disabled, and its text could not be
selected. Refuse input the way TextView does instead: the input drops
its key listener while it is read-only, which leaves no input method,
hardware key or cut and paste able to edit it and keeps it focusable.
TextView reports TYPE_NULL for such a view and marks every EditText
editable for accessibility, so the multiline, secure-text and input-type
reads use the configured type, and the accessibility delegate drops the
editable flag and ACTION_SET_TEXT while the input is read-only.
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 17, 2026
@YevheniiKotyrlo

Copy link
Copy Markdown
Contributor Author

Device evidence — before / after

UNFIXED — from touch mode, the first Tab focuses the First box and the second passes over the read-only TextInput to the Last box; a long press on the input's first word selects nothing.

FIXED — the second Tab stops on the read-only input, and the long press selects the word, offering Copy and no Cut or Paste.

before — main, 96dddb0feb after — with this PR

Screen recordings of RNTester debug builds of main and of this PR's head on an Android 16 (API 36) emulator, 1140×2400 at density 480. In the first row Tab is pressed twice from touch mode in a scene of two Pressables with a TextInput that has editable={false} between them, above a line naming the one that holds focus; in the second row the same kind of input is long-pressed on its first word, above a line showing the selection onSelectionChange reports.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant