MUIOTPInput
MUIOTPInput renders a one-time-password field as length individual
TextField boxes, one per
character, backed by a single string value with no separators.
Working
MUIOTPInput works as follows:
-
Typing a character fills the current box and auto-advances focus to the next one.
-
Backspace on an empty box clears the previous box and moves focus back to it.
-
Arrow Left / Right move focus between boxes without changing the value.
-
Focusing a box selects its character, so typing replaces it instead of appending.
-
Pasting a code distributes its characters across the remaining boxes starting from the box where the cursor is — paste into the first box to fill the whole field.
-
By default only digits are accepted; a non-digit keystroke or paste is ignored. Set
alphanumericto also allow letters. -
separatorIndexesrenders aseparator(default'-') after the given zero-based indexes.E.g.
separatorIndexes={[2, 6]}withlength={10}renders as*** - **** - ***. -
There is no inline label. The label is hidden unless
showLabelAboveFormField(or theallLabelsAboveFieldsconfig) renders it above the boxes; either way the accessible name is applied to every box.
Usage
import MUIOTPInput, { MUIOTPInputProps } from '@nish1896/mui-components/mui/otp-input';const [code, setCode] = useState('');
<MUIOTPInput
fieldName="otp"
value={code}
onValueChange={({ newValue }) => setCode(newValue)}
/>Separators and alphanumeric codes
<MUIOTPInput
fieldName="licenseKey"
value={code}
onValueChange={({ newValue }) => setCode(newValue)}
length={10}
alphanumeric
separatorIndexes={[2, 6]}
separator="–"
textFieldProps={{ size: 'small' }}
/>API
MUIOTPInput does not spread arbitrary TextFieldProps
on itself — use textFieldProps to customize every character box. Props marked with
* are required.
| Name | Type | Description |
|---|---|---|
fieldName* | string | Name/path of the field. Used to derive the id, the default label, and the name attribute. This prop is required for all components. |
value | string | Current code, as a single string with no separators (e.g. '123456'). This is a controlled component — value and onValueChange must be supplied together. undefined is treated as an empty code. Only the first length characters are shown and editable — a longer value (or shrinking length) drops the overflow from the next onValueChange, so keep value.length <= length. |
onValueChange* | ({ newValue, event }) => void | Called after every character entry, deletion, or paste with the next full code string (always length characters or fewer) and the original keystroke, backspace, or paste event. |
length | number | Number of individual character boxes. Default: 6 |
separatorIndexes | number[] | Zero-based character indexes after which a separator is rendered. For example, [2, 6] with length={10} renders as *** - **** - ***. |
separator | ReactNode | Content rendered at each separatorIndexes position.Default: '-' |
alphanumeric | boolean | When true, each box accepts letters and digits. When false, only digits can be typed or pasted — a non-digit keystroke or paste is ignored. Default: false |
textFieldProps | TextFieldProps | TextFieldProps forwarded to every character box — e.g. a custom size, variant or sx. Props the component derives or controls per box (name, id, value, onChange, onKeyDown, onPaste, error, multiline/rows, inputRef/ref) are omitted. |
autoFocus | boolean | When true, focuses the first empty box (or the first box, if the code is already complete) on mount.Default: false |
inputRef | Ref<HTMLInputElement> | Ref to the first character box's <input> element — use it to imperatively focus the field (e.g. React Hook Form's setFocus or focus-on-error handling). |
label | ReactNode | Label displayed for the field. Defaults to a human-readable label derived from fieldName, e.g. firstName becomes "First Name". |
showLabelAboveFormField | boolean | Renders the field label above the boxes. The label is otherwise hidden — there is no inline label, but the accessible name is still applied to every box. Set the value to true to render the FormLabel for this field.Default: false |
formLabelProps | FormLabelProps | FormLabelProps forwarded to the internal FormLabel. The id is managed by the component. Multiple fields can be configured using the ConfigProvider component. |
required | boolean | Indicates that the field is mandatory by adding an asterisk symbol (*) to the form label and setting the relevant accessibility attributes. |
disabled | boolean | When true, disables the field and associated controls. |
errorMessage | string | string[] | Validation error for the field — pass a single message string, or a string[] when the field can fail multiple rules at once (every message is shown together). A non-empty string or array puts the field in an error state; undefined/''/[] clear it. Normalize your form library's error shape to this at the call site (e.g. an RHF FieldError via its .message). Use renderError to customize how the message(s) are rendered. |
renderError | (errors: string[]) => ReactNode | Custom renderer for the resolved error message(s), called only when the field is in an error state. Always receives a string[] — use errors[0] for the common single-message case, or map over errors when a field fails several rules. By default a single message renders as text and multiple messages render on separate lines. |
hideErrorMessage | boolean | If true, hides the error message text while keeping the field in an error state. |
helperText | ReactNode | Content displayed in the FormHelperText component below the field when there is no visible validation error. |
formHelperTextProps | FormHelperTextProps | FormHelperTextProps forwarded to the internal FormHelperText. The id is managed by the component. Multiple fields can be configured using the ConfigProvider component. |
customIds | { field, label, helperText, error } | Overrides the default field, label, helper text, and error IDs used for accessibility. |
Playground
Controlled with plain React state — a 6-digit numeric SMS code with autoFocus,
and a 10-character alphanumeric license key grouped 3–4–3 via
separatorIndexes with a custom separator, showLabelAboveFormField and
textFieldProps.