Skip to main content

Form

The <Form /> component provides a "local" context for the TextInput, FormField and SwitchListItem components.

The provider hosts the hosts the ref values used by the TextInput to know which returnKey and what would be the next field to focus.

Usage


// To manually focus the first invalid field
ref.current?.focusFirstInvalidField()

<Form onSubmit={handleSubmit} ref={ref}>
{...}
</Form>

Example

<Form onSubmit={handleSubmit}>
<TextInput
onChangeText={newText => setFirstName(newText)}
defaultValue={text}
label={<Text>First name:</Text>}
/>

<TextInput
onChangeText={newText => setLastName(newText)}
defaultValue={text}
label={<Text>Last name:</Text>}
/>

<SwitchListItem
label={<Text>Subscribe me to the newsletter</Text>}
value={isSubscribed}
onValueChange={toggleSwitch}
/>

<TextInput
onChangeText={newText => setEmailAddress(newText)}
defaultValue={text}
label={<Text>Email address:</Text>}
/>
</Form>

When the user interacts with this form:

  • The First Name field has returnKeyType="next" and focuses the Last name one when the next button is pressed
  • The Last name has returnKeyType="next" and focuses the Subscribe me to the newsletter switch when the next button is pressed
  • The SwitchListItem does not show any keyboard, but swiping right will focus the email address field
  • The Email address has returnKeyType="done" as is the last field of the form and triggers the onSubmit callback when the done button is pressed

Conditional fields

The field refs are added to the ref in the same order they are added to the DOM, so in the previous example, the order will be:

  1. TextInput - First name
  2. TextInput - Last name
  3. SwitchListItem
  4. TextInput - Email address

This all works fine, but the logic will fail when a component is rendered conditionally as refs are appended to the array, so this edge case needs to be handled manually.

Won't work

<Form onSubmit={handleSubmit}>
<TextInput
onChangeText={newText => setFirstName(newText)}
defaultValue={text}
label={<Text>First name:</Text>}
/>

<SwitchListItem
label={<Text>Show last name</Text>}
value={isLastNameVisible}
onValueChange={toggleLastName}
/>

{isLastNameVisible ? (
<TextInput
onChangeText={newText => setLastName(newText)}
defaultValue={text}
label={<Text>Last name:</Text>}
/>
) : null}

<TextInput
onChangeText={newText => setEmailAddress(newText)}
defaultValue={text}
label={<Text>Email address:</Text>}
/>
</Form>

Last name is conditionally rendered when the Show last name switch is on and will use the returnKeyType="done" as its last element on the ref list.

note

Email address will always be returnKeyType="done" as its value is decided when the component is mounted and doesn't change with next re-render

Let's fix it

To fix the problem, we can manually tell the TextInput the return key to display and the ID or ref of the next element to be focused:

1. Specifying the ID

<Form onSubmit={handleSubmit}>
<TextInput
onChangeText={newText => setFirstName(newText)}
defaultValue={text}
label={<Text>First name:</Text>}
/>

<SwitchListItem
label={<Text>Show last name</Text>}
value={isLastNameVisible}
onValueChange={toggleLastName}
/>

{isLastNameVisible ? (
<TextInput
onChangeText={newText => setLastName(newText)}
defaultValue={text}
label={<Text>Last name:</Text>}
returnKeyType="next"
nextFieldId="email-field" // The next field ID to be focused
/>
) : null}

<TextInput
onChangeText={newText => setEmailAddress(newText)}
defaultValue={text}
label={<Text>Email address:</Text>}
id="email-field" // The field ID
/>
</Form>

2. Specifying the ref

const emailRef = React.useRef(null);

<Form onSubmit={handleSubmit}>
<TextInput
onChangeText={newText => setFirstName(newText)}
defaultValue={text}
label={<Text>First name:</Text>}
/>

<SwitchListItem
label={<Text>Show last name</Text>}
value={isLastNameVisible}
onValueChange={toggleLastName}
/>

{isLastNameVisible ? (
<TextInput
onChangeText={newText => setLastName(newText)}
defaultValue={text}
label={<Text>Last name:</Text>}
returnKeyType="next"
nextFormField={emailRef}
/>
) : null}

<TextInput
onChangeText={newText => setEmailAddress(newText)}
defaultValue={text}
label={<Text>Email address:</Text>}
ref={emailRef}
/>
</Form>;

Props

Required onSubmit

The callback to be called when the TextInput returnKeyboardType is done.

Type
callback

Methods

focusFirstInvalidField

Focuses the first field of the Form that has been marked as invalid

// To manually focus the first invalid field
const focusInvalidField = () => {
ref.current?.focusFirstInvalidField()
}

<Form onSubmit={handleSubmit} ref={ref}>
<Pressable onPress={focusInvalidField} />
</Form>