OTP input
Free · MITReact Native · ExpoA verification code field where digits pop in, a pending check breathes, success ripples across the cells and a wrong code shakes and clears.
Try it on your phone
Scan to open this demo in your phone's browser and use it with your fingers.Installation
$ npx shadcn@latest add https://goodui.dev/native/r/otp-input.jsonThen run npx expo install --fix so react-native-reanimated match your Expo SDK. Files land in components/goodui-native/otp-input.
Usage
import { OtpInput } from "@/components/goodui-native/otp-input/otp-input";
<OtpInput autoFocus onComplete={(code) => api.verify(code)} />When to use
Use it for
- Sign in and sign up verification, two factor codes, email confirmation codes.
Reach for something else
- Passwords or PINs that must stay hidden: use a secure text field.
- Codes with letters: this field accepts digits only.
API reference
| Prop | Type | Default |
|---|---|---|
| length Number of digits. Default 6. | number | 6 |
| onComplete* Called when every cell is filled. Return a promise: resolve to accept the code, reject to shake, clear and try again. | (code: string) => unknown | — |
| onChange Called on every change. | (code: string) => void | — |
| autoFocus Focus the field and open the keyboard on mount. | boolean | false |
| errorText Message under the cells after a rejected code. Same as `labels.error`. | string | — |
| labels Overrides for the built-in strings; a GooduiLocaleProvider pack sets them app-wide. | Partial<OtpInputLabels> | — |
| accessibilityLabel Overrides the label read by screen readers. | string | — |
| style Style for the outer container. | StyleProp<ViewStyle> | — |
| testID Identifier for end-to-end tests. | string | — |
Motion and haptics
- Digits land with a small pop on the bouncy spring; the active cell has a blinking caret and an accent border.
- While a returned promise is pending the cells breathe in a cascade.
- Success ripples a scale wave across the cells and tints them green; an error tints them red and shakes the row.
- Reduced motion: no pop, wave, breathing or shake; colors still change.
- Haptic: success when the code is accepted
- Haptic: error when it is rejected
- Each cell animates on the UI thread; typing re-renders only the cells.
Accessibility
- One real TextInput owns the keyboard, paste, iOS one-time-code and Android SMS autofill, and the screen reader label ('Verification code, 6 digits').
- The cells are hidden from screen readers. Results are announced.
Notes for AI
- Return a promise from onComplete: resolve to accept, reject to shake and clear. Do not manage error state yourself.
- Do not wrap it in another TextInput or add your own keyboard handling.