Skip to content

Proposal: Declarative submit and clear props for TextInput #7330

@rozele

Description

@rozele

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:

  1. React Native does not support the onSubmitEditing event for multiline TextInput.
  2. 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:

  1. A clearTextOnSubmit prop that works similarly to the blurTextOnSubmit prop in TextInput, except that it simply clears the field after sending the onSubmitEditing event.
  2. A submitKeyEvents prop that registers a set of KeyEvents that may trigger onSubmitEditing in 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 pressed

We'll want to retain backward compatible behaviors, so the following defaults should be implemented:

  1. submitKeyEvents should be ignored for single-line TextInput.
  2. submitKeyEvents should be [] by default (so no keys trigger submit in multiline)
  3. clearTextOnSubmit should 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:

  1. User types 'a' (nativeEventCount = 1)
  2. User types 'Enter'
  3. onSubmitEvent dispatched
  4. User types 'b' (nativeEventCount = 2)
  5. TextInput onSubmitEvent callback called, sees nativeEventCount = 1
  6. 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

  1. Should single-line TextInput support submitKeyEvents?
  2. 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.
  3. Is there a way to integrate this into the key[Down|Up]Events approach 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!)

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions