Skip to content

Keep an email field's cursor hidden on Xiaomi Android 10 when caretHidden changes - #59124

Open
YevheniiKotyrlo wants to merge 1 commit into
react:mainfrom
YevheniiKotyrlo:fix/android-email-caret-hidden
Open

YevheniiKotyrlo wants to merge 1 commit into
react:mainfrom
YevheniiKotyrlo:fix/android-email-caret-hidden

Conversation

@YevheniiKotyrlo

@YevheniiKotyrlo YevheniiKotyrlo commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary:

On Xiaomi devices running Android 10, React Native hides the cursor of an email-address TextInput, a workaround for a crash in MIUI (#27204). Any later update of caretHidden, caretHidden={false} included, undoes it and the cursor comes back.

setCaretHidden is meant to leave the workaround alone, and checks view.stagedInputType == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS. setKeyboardType stages the variation together with TYPE_CLASS_TEXT, so the check never holds. Whether the cursor comes back also depends on the order the two props are applied in, since the check reads a staged type the keyboard type may not have reached yet.

Whether the cursor shows is one decision over two props, so this makes it once. setCaretHidden only stages its value (stagedCaretHidden, beside stagedAutoCapitalize), setKeyboardType no longer touches the cursor, and onAfterUpdateTransaction sets isCursorVisible after the input type is committed: visible unless caretHidden, or unless the committed type is a text field with the email variation on Xiaomi Android 10, read through TYPE_MASK_CLASS and TYPE_MASK_VARIATION.

Changelog:

[ANDROID] [FIXED] - Keep an email-address TextInput's cursor hidden on Xiaomi Android 10 when caretHidden changes

Test Plan:

ReactTextInputPropertyTest gains three cases: caretHidden hides and shows the cursor; on Xiaomi Android 10 (@Config(sdk = [Q]) with ShadowBuild.setManufacturer("Xiaomi")) an email field's cursor stays hidden after a caretHidden update, which fails on main (expected false but was true); and caretHidden still applies to a non-email field there. The ReactAndroid unit suite and ktfmt pass.

On a Xiaomi Mi MIX 3 (Android 10, API 29, MIUI 12), with RNTester release builds of main and of this PR running the Playground below: focus the field, type a, then press the button twice. With main the cursor is drawn again and blinks (2 different images of the field in 10 screenshots); with this PR it stays hidden (1). Two runs of each agree, and the captures and readings are in this comment. Typing @ afterwards crashed neither build on this MIUI version, so the crash in #27204 itself did not reproduce here.

packages/rn-tester/js/examples/Playground/RNTesterPlayground.js
/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict-local
 * @format
 */

import type {RNTesterModuleExample} from '../../types/RNTesterTypes';

import RNTesterText from '../../components/RNTesterText';
import ExampleTextInput from '../TextInput/ExampleTextInput';
import * as React from 'react';
import {useState} from 'react';
import {Button, StyleSheet, View} from 'react-native';

function Playground() {
  const [text, setText] = useState('');
  const [caretHidden, setCaretHidden] = useState(false);
  return (
    <View style={styles.container}>
      <ExampleTextInput
        testID="email-input"
        autoCapitalize="none"
        caretHidden={caretHidden}
        keyboardType="email-address"
        placeholder="email"
        onChangeText={setText}
      />
      <Button
        testID="toggle-caret-hidden"
        title={`caretHidden: ${String(caretHidden)}`}
        onPress={() => setCaretHidden(hidden => !hidden)}
      />
      <RNTesterText>text: {JSON.stringify(text)}</RNTesterText>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    padding: 10,
    rowGap: 8,
  },
});

export default {
  title: 'Playground',
  name: 'playground',
  description: 'Test out new features and ideas.',
  render: (): React.Node => <Playground />,
} as RNTesterModuleExample;

…dden changes

setCaretHidden left an email field alone only when its staged input type
equalled TYPE_TEXT_VARIATION_EMAIL_ADDRESS, which an email field's type,
carrying TYPE_CLASS_TEXT too, never does, so any caretHidden update showed
the cursor the react#27204 workaround hides. The cursor is now set once per
update, in onAfterUpdateTransaction after the input type is committed, from
caretHidden and the committed type's class and variation.
@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 16, 2026
@YevheniiKotyrlo

YevheniiKotyrlo commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor Author

Device evidence — before / after

UNFIXED — After caretHidden goes true and back to false, the email field draws its cursor and insertion handle again.

FIXED — The cursor stays hidden.

before — main after — with this PR

Xiaomi Mi MIX 3, Android 10 (API 29), MIUI 12: RNTester release builds of main and of this PR running the Playground from the description, captured after typing a and pressing the button twice. After the second press the field shows 2 different images in 10 screenshots with main and 1 with this PR; the builds, the steps and every reading are on this page.

@YevheniiKotyrlo
YevheniiKotyrlo marked this pull request as ready for review October 16, 2026 01:40
@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 Oct 16, 2026

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. 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.

1 participant