-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Proposal: Declarative submit and clear props for TextInput
This is a proposal to add a few props to support common keyboard-based input scenarios. Many applications, such as chat applications, require a TextInput field that submits and clears text when the 'Enter' key is pressed. Often these applications use modifier keys like Shift to support carriage return when multiline text entry is needed. This proposal is to enable applications with these scenarios.
Summary
There are a couple limitations in React Native to effectively supporting these scenarios:
- React Native does not support the
onSubmitEditingevent for multiline TextInput. - React Native does not have a synchronous means to clear the TextInput when the TextInput is "submitted".
I'd like to see the addition of the following APIs:
- A
clearTextOnSubmitprop that works similarly to theblurTextOnSubmitprop in TextInput, except that it simply clears the field after sending theonSubmitEditingevent. - A
submitKeyEventsprop that registers a set of KeyEvents that may triggeronSubmitEditingin a multiline scenario, e.g.:
{ code: 'Enter' } // submit in multiline mode when the Enter key is pressed, but not e.g. Shift+Enter
{ code: 'Enter', shiftKey: true } // submit when Shift+Enter is pressedWe'll want to retain backward compatible behaviors, so the following defaults should be implemented:
submitKeyEventsshould be ignored for single-line TextInput.submitKeyEventsshould be[]by default (so no keys trigger submit in multiline)clearTextOnSubmitshould be false.
If we eventually want to support submitKeyEvents for single-line TextInput, we could make the default value be [{code: 'Enter'}], though we'd also need a way to "ignore" modifier keys, but this does not have to be solved here.
Motivation
Until we can support synchronous events in React Native, the following race condition will always exist:
const [ text, setText ] = useState('');
<TextInput
value={text}
onChangeText={setText}
onSubmitEditing={() => setText('')} />With this very basic example, the following sequence of events may occur:
- User types 'a' (nativeEventCount = 1)
- User types 'Enter'
onSubmitEventdispatched- User types 'b' (nativeEventCount = 2)
- TextInput
onSubmitEventcallback called, sees nativeEventCount = 1 - TextInput sets value to empty string, ignored by native control due to nativeEventCount mismatch (see code)
To the question of "Why should this be done for Windows-only?" The answer is it's probably generally applicable to all react-native platforms, but desktop platforms like react-native-windows and react-native-macos are great proving grounds for the API :). Race conditions for clearing TextInput has been reported for Android at least:
facebook/react-native#30319
facebook/react-native#30692
Basic example
With this proposal, the following would be possible:
const [ text, setText ] = useState('');
<TextInput
value={text}
onChangeText={setText}
multiline
clearTextOnSubmit
submitKeyEvents={[{code: 'Enter', shiftKey: true}]}
onSubmitEditing={sendMessage} />This would create a multiline TextInput that invokes onSubmitEditing then synchronously clears the input whenever the user presses Shift+Enter. The TextInput still allows carriage returns with the Enter key. Obviously we could switch these keys and set submitKeyEvents to [{code: 'Enter'}] so that the TextInput submits when Enter is pressed, but adds carriage return when pressing any modifier key with Enter.
Open Questions
- Should single-line TextInput support
submitKeyEvents? - This is great, but it does not solve the general problem of controlled behavior for TextInput (e.g., what about a button that sends and clears the content of a TextInput). This is by no means an attempt to solve all problems with JS controlled behavior in TextInput, but does ease the pain of a pretty common keyboard-driven scenario.
- Is there a way to integrate this into the
key[Down|Up]Eventsapproach by refactoring and adding a few "actions"? E.g.:
const [ text, setText ] = useState('');
const keyDownEvents = [
{ code: 'Enter', shiftKey: true, action: TextInputActions.Submit | TextInputActions.Clear },
];
<TextInput
value={text}
onChangeText={setText}
multiline
keyDownEvents={keyDownEvents}
onSubmitEditing={sendMessage} />I think 3. would not be worthwhile given the potential for synchronous events with Fabric making most of this irrelevant (though I do still believe we should have the behavior described above for Paper even knowing Fabric may offer a better solution!)