Skip to main content

Form

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

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

Usage

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

Example

import { Form, TextInput } from '@react-native-ama/forms';
import { SwitchListItem } from '@react-native-ama/react-native';

const ExampleForm = () => {
return (
<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>}
/>
<FormSubmit accessibilityLabel="Submit">
<CustomSubmitButton />
</FormSubmit>
</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

ref (optional)

The form provider reference provides access to focusFirstInvalidField and focusFieldAt methods.

TypeDefault
React.RefObject<FormActions>undefined

Methods (FormActions)

focusFirstInvalidField

This method lets you manually shift the focus to the first field that has an error.

focusFirstInvalidField: () => void;

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

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

focusFieldAt

This method lets you manually shift the focus to any field controlled by the form. Simply call the method with the fieldNumber reference which is the zero-based index of the field in the list.

focusFieldAt: (fieldNumber: number) => void;