Skip to main content
Version: v0.30.x

OtpField

OtpField is a React Native OTP input: the one-time code from a text message or an authenticator app, a box per character. It's the step after PhoneField in a phone sign-in.

One text field sits under the boxes, so everything a text field does works: the keyboard offers the code from the latest text message (iOS, Android and Safari), long-press pastes, and screen readers hear one field rather than six. The boxes look like the design's text fields.

import { OtpField } from '@elik56a/react-native-pickers';
Loading…
<View style={{ gap: 12 }}>
  <OtpField value={code} onChange={setCode} onComplete={setSent} />
  <Text>{sent ? `Checking ${sent}…` : 'Enter the 6-digit code'}</Text>
</View>

Paste Your code is 482-913 and the boxes fill with 482913: the field keeps only the characters a code can have.

Try the props​

Platform
length
inputMode
error
<OtpField value={code} onChange={setCode} onComplete={verify} />

Checking the code​

onComplete fires once the user fills the last box, with the whole code: send it to your server there. onChange fires on every key, delete and paste, for a controlled field. Neither fires when you change value yourself.

For a wrong code, set error and value to '': the boxes turn red and empty, the message shows under them, and the field stays focused for another try. Clear error in onChange, so it goes once the user types again. helperText sits under the boxes until there's an error message, a good place for where the code was sent. To hide the keyboard while you check, call Keyboard.dismiss() in onComplete.

Loading…
<OtpField
  length={4}
  value={code}
  onChange={(next) => {
    setCode(next);
    setError('');
  }}
  onComplete={(full) => {
    if (full === CORRECT) {
      Keyboard.dismiss();
      return;
    }
    setError('That code didn’t match. Try again.');
    setCode('');
  }}
  error={error}
  helperText="Sent to •••• 0123. Hint: 1234"
/>

error={true} marks the boxes red without a message. Screen readers hear the error after the field's name, and the message is announced as it appears.

Letters, and PINs​

inputMode="text" takes letters and digits on the full keyboard, for codes like A7K2Q9. secureTextEntry shows each character as a dot, for a PIN.

Loading…
<View style={{ gap: 16 }}>
  <OtpField inputMode="text" length={6} accessibilityLabel="Backup code" />
  <OtpField secureTextEntry length={4} accessibilityLabel="PIN" />
</View>

Designs​

iOSMaterialWeb
bordered boxes, the focused one in the primary colouroutlined boxes, the focused one with a 2dp primary outlinecompact outlined boxes, the focused one with a focus ring

Each box is up to 56 wide and as tall as the design's fields, sharing the row's width, so six fit on the narrowest phone. Restyle any part with styles.

Accessibility​

Screen readers see one text field, named by accessibilityLabel, with the code as its value and the error message as its hint; the boxes are hidden from them, and a new error is announced. Typing, deleting and pasting work as in any field, with a hardware keyboard too.

Props​

PropTypeDefaultDescription
valuestring—The code so far (controlled).
defaultValuestring''Starting code when value isn't set.
onChange(code: string) => void—As the user types, deletes or pastes.
onComplete(code: string) => void—Once the user fills the last box.
lengthnumber6How many characters the code has.
inputMode'numeric' | 'text''numeric'Digits on a number pad, or letters and digits.
secureTextEntrybooleanfalseDots instead of characters.
autoFocusbooleanfalseFocus the field when it mounts.
disabledbooleanfalseDims the boxes and ignores typing.
errorstring | boolean—Shows the boxes as invalid, with the message under them when it's a string. See Checking the code.
helperTextstring—Shown under the boxes, replaced by the error message.
accessibilityLabelstring'Verification code'What screen readers call the field.
theme / designSee Theming and Designs.
styleStyleProp<ViewStyle>—The field's container.
styles{ container, cell, focusedCell, filledCell, cellText, caret, helperText }—Slot styles. container is the row of boxes; helperText the line under them.
testIDstring—On the text input; box i gets ${testID}-cell-${i}.