Skip to content

fix(android): preserve cursor position when centered TextInput is cleared#56615

Open
HarshitMadhav wants to merge 1 commit intofacebook:mainfrom
HarshitMadhav:fix/android-centered-textinput-cursor
Open

fix(android): preserve cursor position when centered TextInput is cleared#56615
HarshitMadhav wants to merge 1 commit intofacebook:mainfrom
HarshitMadhav:fix/android-centered-textinput-cursor

Conversation

@HarshitMadhav
Copy link
Copy Markdown

Summary:

On Android, clearing a TextInput with textAlign: "center" caused the cursor to jump to the right edge of the field instead of staying centered. iOS was not affected. See #55457 for a video reproduction.

The cause is setText(null) in ReactEditText.maybeSetText. On AppCompatEditText, that call replaces the underlying Editable buffer with a freshly constructed one, and the new buffer doesn't carry forward the gravity-based caret positioning that Gravity.CENTER_HORIZONTAL relies on. The cursor then snaps to the layout's natural edge — the right side for LTR centered text — until the user taps the field again.

This PR fixes the issue by clearing the text in place on the existing Editable rather than swapping the buffer:

  • BaseInputConnection.removeComposingSpans(currentText) — preserves the original "some buggy keyboards don't clear the composing text on their own" intent that motivated the original setText(null).
  • currentText.replace(0, currentText.length, "") — empties the buffer without re-creating it.

This mirrors the approach already used a few lines below for the non-empty branch (checkNotNull(text).replace(0, length(), spannableStringBuilder)), so the empty-text path is now consistent with the non-empty path. Gravity is preserved on the same Editable, so the cursor stays centered (or right-aligned for RTL) after clearing.

Fixes #55457.

Changelog:

[ANDROID] [FIXED] - Cursor no longer jumps to the right edge when a centered TextInput is cleared

Test Plan:

Added a Robolectric regression test ReactTextInputPropertyTest.testClearingTextPreservesEditableBufferAndGravity that:

  1. Applies textAlign: "center" and asserts gravity is Gravity.CENTER_HORIZONTAL.
  2. Sets the text to "hello" via ReactTextUpdate and captures view.editableText as bufferBeforeClear.
  3. Clears the text via another ReactTextUpdate with an empty string.
  4. Asserts view.editableText is the same instance as bufferBeforeClear — this is the discriminating behavioral guarantee of the fix vs. setText(null), which would replace the buffer.
  5. Asserts the text is empty, gravity is still centered, and selectionStart/selectionEnd are both 0.

The test is a true regression test:

  • Passes against the fix.
  • Fails against the original text = null code with Expecting actual: hello and actual: "" to refer to the same object.

Ran:

./gradlew :packages:react-native:ReactAndroid:testDebugUnitTest \
  --tests "com.facebook.react.views.textinput.ReactTextInputPropertyTest"

Result:

BUILD SUCCESSFUL
tests=23 skipped=0 failures=0 errors=0

All 22 pre-existing tests in the class continue to pass, so no behavior is regressed by the fix.

@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 Apr 26, 2026
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Apr 26, 2026
@HarshitMadhav HarshitMadhav force-pushed the fix/android-centered-textinput-cursor branch from 6486b7d to d352c57 Compare April 26, 2026 22:35
…ared

On Android, clearing a TextInput with `textAlign: "center"` caused the
cursor to jump to the right edge of the field instead of staying
centered. The cause was `setText(null)` in `ReactEditText.maybeSetText`,
which replaces the underlying `Editable` buffer; recreating the buffer
loses the gravity-based caret positioning that `Gravity.CENTER_HORIZONTAL`
relies on.

Instead of swapping the buffer, remove any composing spans from the
existing `Editable` (preserving the original "buggy keyboards don't
clear composing text" intent) and clear its contents in place via
`Editable.replace(...)`. This mirrors the approach already used by the
non-empty branch a few lines below and keeps gravity-based positioning
intact, so the cursor stays centered (or right-aligned for RTL/right
gravity) after clearing.

Adds a Robolectric regression test in `ReactTextInputPropertyTest`
that asserts the underlying `Editable` instance is preserved across a
clear (the discriminating behavioral difference vs. `setText(null)`).
The test was verified to fail against the original buggy code and pass
against the fix.

Fixes facebook#55457.
@HarshitMadhav HarshitMadhav force-pushed the fix/android-centered-textinput-cursor branch from d352c57 to 712bf0b Compare April 26, 2026 22:46
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. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐛 Android: Cursor jumps to right when clearing centered TextInput

1 participant