skip to content

In a React Native checkout form, how do you move focus to the next TextInput when the user presses the keyboard's return key?

level: middleimportance: must knowfreq 58%

answer

  1. label the key, then handle it
  2. returnKeyType next, last one done
  3. onSubmitEditing calls ref.focus()
  4. submitBehavior submit keeps the keyboard
  5. number pads have no return key on iOS

basics

~10 s

Give each field returnKeyType="next" (the last "done"), and in onSubmitEditing call the next field's ref.current?.focus(). Set submitBehavior="submit" on the chained fields so the keyboard stays up between them instead of blurring and reopening.

solid answer

~40 s

`returnKeyType` only changes the key's label; the behaviour comes from `onSubmitEditing`, which fires when the return key is pressed, and a ref to the next field whose `focus()` you call there. For single-line inputs `submitBehavior` defaults to `'blurAndSubmit'`, which dismisses focus before your handler moves it, so chained fields use `submitBehavior="submit"` to keep the keyboard open; the last field keeps the default and submits the form. `blurOnSubmit` is the deprecated predecessor and is overridden by `submitBehavior`. `enterKeyHint` is the web-style alternative and takes precedence over `returnKeyType`. One trap: iOS number and phone pads have no return key. React Native adds a toolbar button above them only when the field sets a `returnKeyType` such as `'next'` or `'done'`; without one, `onSubmitEditing` never fires.

code

tsx · 43 lines
tsx
import {useRef, type ComponentRef} from 'react';
import {TextInput, View} from 'react-native';

type InputRef = ComponentRef<typeof TextInput>;

export function AddressForm({onPlaceOrder}: {onPlaceOrder: () => void}) {
  const unitRef = useRef<InputRef>(null);
  const postcodeRef = useRef<InputRef>(null);
  const phoneRef = useRef<InputRef>(null);

  return (
    <View>
      <TextInput
        placeholder="Street address"
        returnKeyType="next"
        submitBehavior="submit"
        onSubmitEditing={() => unitRef.current?.focus()}
      />
      <TextInput
        ref={unitRef}
        placeholder="Apartment or unit"
        returnKeyType="next"
        submitBehavior="submit"
        onSubmitEditing={() => postcodeRef.current?.focus()}
      />
      <TextInput
        ref={postcodeRef}
        placeholder="Postcode"
        returnKeyType="next"
        submitBehavior="submit"
        onSubmitEditing={() => phoneRef.current?.focus()}
      />
      {/* On iOS the phone pad has no return key; returnKeyType adds a toolbar button. */}
      <TextInput
        ref={phoneRef}
        placeholder="Phone for the courier"
        keyboardType="phone-pad"
        returnKeyType="done"
        onSubmitEditing={onPlaceOrder}
      />
    </View>
  );
}

go deeper

for a junior

Recall that returnKeyType only labels the key and that onSubmitEditing plus a ref's focus() does the actual moving.

for a middle

Explain submitBehavior's defaults for single-line and multiline fields, why submit avoids the keyboard bounce, and that blurOnSubmit is deprecated.

for a senior

Handle the iOS number-pad case with a returnKeyType toolbar button, keep focused fields visible, and keep a visible submit path for users who never use the return key.

for a principal

Standardise a form field component that encodes these conventions, so every team gets consistent keyboard flow without re-learning platform quirks.

## The pieces A good mobile form lets the user go from field to field with the keyboard's return key, without tapping each field. In React Native that takes four props and a ref per field: - **`returnKeyType`** sets the **label** of the return key: `'next'`, `'done'`, `'go'`, `'search'` and `'send'` work on both platforms; others are platform-specific. - **`onSubmitEditing`** is called when the return key is pressed; its `nativeEvent.text` is the field's text. - **A ref** to each `TextInput`, so the handler can call **`focus()`** on the next field. - **`submitBehavior`** decides what pressing return does to the current field. - **`enterKeyHint`** is the web-style name for the same label (`'next'`, `'done'`, `'enter'` and others). It takes precedence over `returnKeyType` if both are set; pick one. ## submitBehavior and why it matters `submitBehavior` accepts `'submit'`, `'blurAndSubmit'` and `'newline'`. | Field | Default when unset | Effect of return | |---|---|---| | single-line | `'blurAndSubmit'` | fires `onSubmitEditing`, then the field loses focus | | multiline | `'newline'` | inserts a newline; no submit | | any, set to `'submit'` | | fires `onSubmitEditing`, keeps focus | For a single-line field, `'newline'` is not meaningful and is treated as `'blurAndSubmit'`. With the single-line default, pressing return blurs the current field. Moving focus to the next field then reopens the keyboard, which can show as a visible dismiss-and-show bounce. Setting **`submitBehavior="submit"`** on every field except the last keeps the keyboard up while focus moves. The last field keeps the default so return dismisses the keyboard and submits. `blurOnSubmit` is the **deprecated** boolean this replaced. `submitBehavior` overrides it when both are present, so new code should not use `blurOnSubmit`. ## Wiring a four-field checkout form A grocery checkout asks for a street address, an apartment or unit, a postcode and a phone number for the courier. 1. Create a ref per field that needs to be focused programmatically. 2. Give the first three fields `returnKeyType="next"` and `submitBehavior="submit"`. 3. In each `onSubmitEditing`, call the next ref's `focus()`. 4. Give the last field `returnKeyType="done"` and let its `onSubmitEditing` validate and place the order. Refs are typed as the component's instance: `ComponentRef<typeof TextInput>` works everywhere, and under the Strict TypeScript API `TextInputInstance` is exported for the same purpose. ## The number-pad trap on iOS On iOS, the **number, decimal and phone pads have no return key**. A phone field with `keyboardType="phone-pad"` and no `returnKeyType` therefore gives the user no way to trigger `onSubmitEditing`, and the docs note that the method is not called for `phone-pad`. React Native works around this: when a field on one of those pads has a `returnKeyType` such as `'next'` or `'done'` set, its iOS text input adds a **toolbar above the keyboard with a button** labelled after that return key type, and pressing it submits just as a return key would. `inputAccessoryViewButtonLabel` replaces the button's label, which is not localized by default. The toolbar is an iOS-only workaround inside React Native's text input. ## Other details worth knowing - **Focus on mount** with `autoFocus` on the first field rather than calling `focus()` in an effect. - **`blur()`** and **`isFocused()`** are the companion methods on the same ref. - **Keep the focused field visible.** Moving focus down a long form means the next field may be under the keyboard; avoiding that is keyboard-avoidance work, separate from focus chaining. - **Do not rely on the return key alone.** A visible **Continue** button is still needed for users who dismiss the keyboard or use assistive technology. ## Checklist for a keyboard-friendly form - every field except the last: `returnKeyType="next"`, `submitBehavior="submit"`, `onSubmitEditing` focusing the next ref; - the last field: `returnKeyType="done"` (or `'go'`/`'send'`), default `submitBehavior`, `onSubmitEditing` submitting; - number and phone fields on iOS: a `returnKeyType` set so the toolbar button appears, with `inputAccessoryViewButtonLabel` if the label must be localized; - no `blurOnSubmit` in new code; - a visible submit button regardless of keyboard flow.

  • In React Native, why does the keyboard briefly close and reopen when onSubmitEditing focuses the next single-line TextInput?
    A single-line field's `submitBehavior` defaults to `'blurAndSubmit'`: pressing return fires `onSubmitEditing` and then blurs the field, so the keyboard can start to dismiss before the next field takes focus and brings it back. Setting `submitBehavior="submit"` on the chained fields submits without blurring, so focus moves while the keyboard stays open.
  • In React Native, what happens if a TextInput sets both enterKeyHint and returnKeyType?
    `enterKeyHint` wins: `TextInput` maps it to a return key type and ignores `returnKeyType`. The two exist because `enterKeyHint` mirrors the web attribute name while `returnKeyType` is React Native's original prop, with more platform-specific values. Use one consistently in a codebase.
  • In React Native on iOS, how does a phone-pad TextInput let the user submit, given the pad has no return key?
    If the field sets a `returnKeyType` such as `'next'` or `'done'`, React Native's iOS text input adds a toolbar above the number or phone pad with a button named after it, and pressing it fires `onSubmitEditing` like a return key. Without a `returnKeyType` there is no toolbar and no way to submit from the keyboard. `inputAccessoryViewButtonLabel` provides a localized label.

saying these in an interview costs you the question

  • returnKeyType="next" moves focus to the next field automatically.
  • blurOnSubmit is the current way to keep the keyboard open between fields.
  • onSubmitEditing fires for every keyboard type on iOS without extra setup.
  • submitBehavior 'newline' makes a single-line field insert a line break.
  • Focus chaining needs a third-party library in React Native.