Migration
Version 8 keeps the original MuiOtpInput API and adds Base UI, shadcn, headless, and form entrypoints next to it.
From mui-one-time-password-input
This package continues viclafouch/mui-otp-input, published as mui-one-time-password-input. Swap the package and the import; your props keep working.
pnpm remove mui-one-time-password-input
pnpm add @wh1teee/mui-otp-input- import { MuiOtpInput } from 'mui-one-time-password-input';
+ import { MuiOtpInput } from '@wh1teee/mui-otp-input';Every prop of the original component — value, length, autoFocus, onChange, onComplete, onBlur, validateChar, and TextFieldsProps — keeps its name and meaning, and the root still accepts Material UI Box props. Material UI 7 and 9 and React 18 and 19 are supported.
What you gain
Optional props. Nothing changes until you use them.
| Prop | What it does |
|---|---|
validationType | Built-in numeric or alphanumeric policy instead of a hand-written validateChar. |
pastePreprocess | Cleans pasted and autofilled text before character rules run. |
transformChar | Maps characters before validation, for example to upper case. |
onInvalid | Reports rejected typing and paste so you can explain why. |
autoFocus={ms} | Delays first-slot focus until a dialog or transition settles. |
ariaLabel, slotAriaLabel | Names the group and announces each slot position. |
name, form, autoSubmit | Native form submission and reset, opt-in submit on completion. |
mask | Renders slots as password inputs. |
// Before: digits were enforced by hand.
<MuiOtpInput
length={6}
value={code}
onChange={setCode}
validateChar={(character) => /^\d$/.test(character)}
/>
// After: the built-in policy, a cleaned paste, and a named group.
<MuiOtpInput
ariaLabel="Verification code"
length={6}
value={code}
onChange={setCode}
validationType="numeric"
pastePreprocess="digits-only"
/>From @wh1teee/mui-otp-input 5.x
Root imports are unchanged. Version 8 rebased the fork onto upstream v7 and kept its behavior.
- Delayed
autoFocus,transformChar,pastePreprocess, and stable input refs behave as before. /muiis an explicit alias of the root import, for codebases that want the renderer visible in every import.- The explicit form adapter path is
/mui/react-hook-form;/react-hook-formstill works.
Leaving Material UI
Move one screen at a time: both renderers share one behavior contract, so the value your form receives does not change.
- import { MuiOtpInput } from '@wh1teee/mui-otp-input';
+ import { OtpInput } from '@wh1teee/mui-otp-input/shadcn';
+ import '@wh1teee/mui-otp-input/shadcn.css';
- <MuiOtpInput ariaLabel="Code" length={6} value={code} onChange={setCode} />
+ <OtpInput label="Code" length={6} value={code} onValueChange={setCode} />The Base UI field renders its own label and description, defaults to numeric codes, and names change callbacks after Base UI (onValueChange, onValueComplete). Once no screen imports the root or /mui, remove @mui/material and Emotion — the Base UI entrypoints never load them.