Skip to content

Commit 9fac885

Browse files
gabrieldonadelfacebook-github-bot
authored andcommitted
feat: Add inputMode prop to TextInput component (#34460)
Summary: This adds the `inputMode` prop to the TextInput component as requested on #34424, mapping web [inputMode types](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode) to equivalent [keyboardType](https://reactnative.dev/docs/textinput#keyboardtype) values. This PR also updates RNTester TextInputExample in order to facilitate the manual QA. ### Caveats ~~This only adds support to `text`, `decimal`, `numeric`, `tel`, `search`, `email`, and `url` types.~~ #### `inputMode="none"` **Currently mapped to `default` keyboard type.** The main problem with this input mode is that it's not supported natively neither on Android or iOS. Android `TextView` does accept `none` as `android:inputType` but that makes the text not editable, which wouldn't really solve our problem. `UITextInput` on iOS on the other hand doesn't even have something similar to avoid displaying the virtual keyboard. If we really want to add the support for `inputMode="none"` one interesting approach we could take is to do something similar to what WebKit has done (WebKit/WebKit@3b5f0c8). In order to achieve this behavior, they had to return a `UIView` with a bounds of `CGRectZero` as the inputView of the `WKContentView` when inputmode=none is present. ~~I guess the real question here should be, do we really want to add this? Or perhaps should we just map `inputMode="none"` to `keyboardType="default"`~~ Android docs: https://developer.android.com/reference/android/widget/TextView#attr_android:inputType iOS docs: https://developer.apple.com/documentation/uikit/uikeyboardtype?language=objc #### `inputMode="search"` on Android **Currently mapped to `default` keyboard type.** Android `TextView` does not offers any options like `UIKeyboardTypeWebSearch` on iOS to be used as `search` with `android:inputType` and that's probably the reason why `keyboardType="web-search"` is iOS only. I checked how this is handled on the browser on my Android device and it seems that Chrome just uses the default keyboard, maybe we should do the same? ### Open questions - ~~What should be done about `inputMode="none"`?~~ Add it and map it to `default` keyboard type. - ~~Which keyboard should we show on Android when `inputMode="search"`?~~ Use the `default` keyboard the same way Chrome does ## Changelog [General] [Added] - Add inputMode prop to TextInput component ## Test Plan 1. Open the RNTester app and navigate to the TextInput page 2. Test the `TextInput` component through the `Input modes` section https://user-images.githubusercontent.com/11707729/185691224-3042e828-a008-4bd0-bb3d-010a6a18dfd5.mov Pull Request resolved: #34460 Reviewed By: necolas Differential Revision: D38900724 Pulled By: cipolleschi fbshipit-source-id: 60d405ccdbfad588b272fbb6b220b64ffdfc4b14
1 parent 5451cd4 commit 9fac885

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

Libraries/Components/TextInput/TextInput.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,16 @@ export type KeyboardType =
155155
// Android-only
156156
| 'visible-password';
157157

158+
export type InputMode =
159+
| 'none'
160+
| 'text'
161+
| 'decimal'
162+
| 'numeric'
163+
| 'tel'
164+
| 'search'
165+
| 'email'
166+
| 'url';
167+
158168
export type ReturnKeyType =
159169
// Cross Platform
160170
| 'done'
@@ -567,6 +577,23 @@ export type Props = $ReadOnly<{|
567577
*/
568578
enterKeyHint?: ?enterKeyHintType,
569579

580+
/**
581+
* `inputMode` works like the `inputmode` attribute in HTML, it determines which
582+
* keyboard to open, e.g.`numeric` and has precedence over keyboardType
583+
*
584+
* Support the following values:
585+
*
586+
* - `none`
587+
* - `text`
588+
* - `decimal`
589+
* - `numeric`
590+
* - `tel`
591+
* - `search`
592+
* - `email`
593+
* - `url`
594+
*/
595+
inputMode?: ?InputMode,
596+
570597
/**
571598
* Determines which keyboard to open, e.g.`numeric`.
572599
*
@@ -1422,6 +1449,17 @@ const enterKeyHintToReturnTypeMap = {
14221449
send: 'send',
14231450
};
14241451

1452+
const inputModeToKeyboardTypeMap = {
1453+
none: 'default',
1454+
text: 'default',
1455+
decimal: 'decimal-pad',
1456+
numeric: 'number-pad',
1457+
tel: 'phone-pad',
1458+
search: Platform.OS === 'ios' ? 'web-search' : 'default',
1459+
email: 'email-address',
1460+
url: 'url',
1461+
};
1462+
14251463
const ExportedForwardRef: React.AbstractComponent<
14261464
React.ElementConfig<typeof InternalTextInput>,
14271465
React.ElementRef<HostComponent<mixed>> & ImperativeMethods,
@@ -1434,6 +1472,8 @@ const ExportedForwardRef: React.AbstractComponent<
14341472
editable,
14351473
enterKeyHint,
14361474
returnKeyType,
1475+
inputMode,
1476+
keyboardType,
14371477
...restProps
14381478
},
14391479
forwardedRef: ReactRefSetter<
@@ -1449,6 +1489,9 @@ const ExportedForwardRef: React.AbstractComponent<
14491489
returnKeyType={
14501490
enterKeyHint ? enterKeyHintToReturnTypeMap[enterKeyHint] : returnKeyType
14511491
}
1492+
keyboardType={
1493+
inputMode ? inputModeToKeyboardTypeMap[inputMode] : keyboardType
1494+
}
14521495
{...restProps}
14531496
forwardedRef={forwardedRef}
14541497
/>

packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,30 @@ module.exports = ([
721721
return <View>{examples}</View>;
722722
},
723723
},
724+
{
725+
title: 'Input modes',
726+
name: 'inputModes',
727+
render: function (): React.Node {
728+
const inputMode = [
729+
'none',
730+
'text',
731+
'decimal',
732+
'numeric',
733+
'tel',
734+
'search',
735+
'email',
736+
'url',
737+
];
738+
const examples = inputMode.map(mode => {
739+
return (
740+
<WithLabel key={mode} label={mode}>
741+
<TextInput inputMode={mode} style={styles.default} />
742+
</WithLabel>
743+
);
744+
});
745+
return <View>{examples}</View>;
746+
},
747+
},
724748
{
725749
title: 'Blur on submit',
726750
render: function (): React.Element<any> {

0 commit comments

Comments
 (0)