suiss/ui · Interaction
OTP Autofill
A one-time code field that offers an incoming code, fills it digit by digit, and verifies it automatically.
OTP Autofill is an open-source interaction from suiss/ui for React, React Native, SwiftUI and Jetpack Compose. The @esuiss/ui CLI copies its source into your project, so you own the code.
OtpAutofill builds on the suiss/ui InputOTP component to recreate the iOS security code autofill flow. When the field is focused and empty, OtpAutofillSuggestion offers the received code; choosing it types the digits in with a short pop animation and calls onVerify once all slots are filled. A valid code turns the slots green and locks the field; an invalid one shakes the slots, marks them red, then clears the field and refocuses it.
The suggestion adapts to the device through useIsMobile. Below 48rem it docks above the on-screen keyboard like the QuickType bar, tracking the visual viewport; on wider screens it appears as an inline pill under the field. In supporting browsers, the WebOTP API also reads codes from SMS and fills them automatically.
Installation
CLI
Works in any project with a components.json. See Installation for the one-line registry setup. Or use the suiss/ui CLI:
Manual
- Install the dependencies and add the
cnhelper:
-
Add the pieces it builds on: Input OTP,
use-mobile. -
Copy the source into
components/interactions/otp-autofill.tsx:
- Update the import paths to match your project.
Usage
- Place
OtpAutofillInputandOtpAutofillSuggestioninsideOtpAutofill. PassInputOTPGroup,InputOTPSlot, andInputOTPSeparatorfrominput-otpas the input's children. - The value is managed internally. Typing or pasting also verifies automatically once the code reaches
maxLength; a paste of several characters fills with the same animation. onVerifymay be async. UseuseOtpAutofillto readstate(idle,filling,verifying,verified,invalid) for status text or other UI.- Set
codeon the suggestion tonulluntil a code arrives; the suggestion stays hidden without one.
Examples
Wrong code
A rejected code shakes the field, shows an error, clears, and accepts a code typed by hand.
API Reference
OtpAutofill
The root that holds the code value and verification state.
| Prop | Type | Default | Description |
|---|---|---|---|
maxLength | number | Required | The number of characters in the code; verification runs once it is reached. |
onVerify | (code: string) => Promise<boolean> | boolean | Required | Called with the complete code; return or resolve true to accept it or false to reject it. |
webOtp | boolean | true | Listens for SMS codes through the WebOTP API, where supported. |
Also accepts the props of React.ComponentProps<"div">.
OtpAutofillInput
The InputOTP field wired to the autofill state.
| Prop | Type | Default | Description |
|---|---|---|---|
containerClassName | string | - | Classes for the slot container, merged with the state styles. |
children | React.ReactNode | Required | The slot groups and separators that make up the field. |
Also accepts the props of React.ComponentProps<"input">.
OtpAutofillSuggestion
The button that offers the received code and fills it when pressed.
| Prop | Type | Default | Description |
|---|---|---|---|
code | string | null | undefined | Required | The received code to offer; the suggestion is hidden while it is empty. |
source | React.ReactNode | "From Messages" | The label that names where the code came from. |
Also accepts the props of React.ComponentProps<"button">.
Accessibility
- Label the field with
aria-labelonOtpAutofillInput, which renders a single text input. - The input is read-only while filling, verifying, or verified, and sets
aria-invalidwhen the code is rejected. - The suggestion is a native button that is
inertwhile hidden, and it prevents focus from leaving the field on press. - After a rejected code, focus returns to the field. Pair the root with a
role="status"element to announce the result.
Notes
- The root exposes
data-slot="otp-autofill"anddata-state. The suggestion usesdata-slot="otp-autofill-suggestion",data-placement(keyboardorinline), anddata-closedwhile hidden. - The pop and shake animations are skipped under
prefers-reduced-motion.

OtpAutofill wraps an InputOTP and runs it through idle, filling, verifying, verified and invalid states. When the input is focused and empty, OtpAutofillSuggestion slides up above the keyboard with the incoming code; pressing it types the code one digit at a time.
When all digits are entered, onVerify runs and the slots dim while it is pending. A valid code turns the slots green and locks the input. An invalid code turns them red and shakes the row, then clears the input and refocuses it. Pasting or a system autofill of several digits plays the same digit-by-digit fill.
Installation
The CLI also adds what it builds on: Input OTP, Text. On React Native it also adds the animated view components/ui/animated-view.tsx.
Manual
- Install the dependencies:
-
Add the pieces it builds on: Input OTP, Text, and the primitives
components/primitives/keyboard.tsx,components/primitives/portal.tsx, and the animated viewcomponents/ui/animated-view.tsxfrom the next step. -
Copy the animated view into
components/ui/animated-view.tsx:
- Copy the source into
components/interactions/otp-autofill.tsx:
- Update the import paths to match your project.
- Install the dependencies:
-
Add the pieces it builds on: Input OTP, Text, and the primitives
components/primitives/keyboard.tsx,components/primitives/portal.tsx, and the animated viewcomponents/ui/animated-view.tsxfrom the next step. -
Copy the animated view into
components/ui/animated-view.tsx:
- Copy the source into
components/interactions/otp-autofill.tsx:
- Update the import paths to match your project.
- Install the dependencies:
-
Add the pieces it builds on: Input OTP, Text, and the primitives
components/primitives/keyboard.tsx,components/primitives/portal.tsx, and the animated viewcomponents/ui/animated-view.tsxfrom the next step. -
Copy the animated view into
components/ui/animated-view.tsx:
- Copy the source into
components/interactions/otp-autofill.tsx:
- Update the import paths to match your project.
-
Target iOS 17 or later.
-
Add the Swift package to your app:
- Copy the theme files every view uses:
- Copy the source and every file it uses:
- Add the files to your app target.
- Set
minSdkto 24 or higher and add the dependencies:
- Copy the theme files every view uses:
- Copy the source and every file it uses:
- Update the
com.esuiss.uipackage names to match your project.
Usage
Pass maxLength and onVerify, which returns a boolean or a promise of one. Put InputOTPGroup and InputOTPSlots inside OtpAutofillInput, and render an OtpAutofillSuggestion with the code your app received; it hides when code is empty.
The input sets textContentType="oneTimeCode" and the platform's one-time code autoComplete, so the system can also offer the code. useOtpAutofill returns state, value, fill and inputRef for custom controls.
Examples
Wrong code
An incoming code that fails verification, showing the shake and reset.

Four digits
A four-digit code with its own suggestion.

API Reference
OtpAutofill
The root that holds the code and verification state.
| Prop | Type | Default | Description |
|---|---|---|---|
maxLength | number | Required | Number of digits in the code. |
onVerify | (code: string) => Promise<boolean> | boolean | Required | Checks a complete code; return true when it is valid. |
Also accepts the props of React.ComponentProps<typeof View>.
OtpAutofillInput
The InputOTP that shows each state and shakes on an invalid code.
| Prop | Type | Default | Description |
|---|---|---|---|
containerClassName | string | - | Classes for the animated container around the input. |
children | React.ReactNode | Required |
Also accepts the props of React.ComponentProps<typeof InputOTP>.
OtpAutofillSuggestion
A bar above the keyboard that fills the suggested code on press.
| Prop | Type | Default | Description |
|---|---|---|---|
code | string | null | undefined | Required | The code to suggest, or null to hide the bar. |
source | React.ReactNode | "From Messages" | Label above the code. Defaults to From Messages. |
portalHost | string | - | Name of a portal host to render into. |
className | string | - |
Also accepts the props of React.ComponentProps<typeof Pressable>.
Accessibility
accessibilityLabelonOtpAutofillInputis passed to the underlying text input.- The suggestion bar has the
buttonrole. - The input is read-only while filling, verifying and after a valid code.
Notes
- Invalid slots use
border-destructivewith abg-destructivetint that is stronger in dark mode; verified slots useborder-green-500andbg-green-500/10 dark:bg-green-500/20. - The suggestion bar uses
bg-popover, orbg-mutedin dark mode, and sits on the keyboard or above the bottom safe area. - Slide and shake animations respect the system reduce motion setting.


