MuiOtpInputElement
A mui-one-time-password-input field connected to React Hook Form that stores the code as one string, with length checks and error display.
MuiOtpInputElement renders MuiOtpInput from mui-one-time-password-input and stores the code in React Hook Form as a single string, such as "482913". It accepts all MuiOtpInput props, including length, validateChar, onComplete and TextFieldsProps. To build your own code field, use useMuiOtpInputAdapter.
Import
import { MuiOtpInputElement } from "@piplup/rhf-adapters/mui-one-time-password-input";Usage
"use client";import Stack from "@mui/material/Stack";import { MuiOtpInputElement } from "@piplup/rhf-adapters/mui-one-time-password-input";import { MuiButtonElement } from "@piplup/rhf-adapters/mui-material";import { useForm } from "react-hook-form";export default function Page() { const { control, handleSubmit } = useForm({ defaultValues: { code: "" } }); return ( <form onSubmit={handleSubmit((values) => alert(JSON.stringify(values, null, 2)), )} > <Stack direction="column" spacing={2}> <MuiOtpInputElement control={control} name="code" length={6} /> <div> <MuiButtonElement control={control} type="submit" variant="contained"> Submit </MuiButtonElement> </div> </Stack> </form> );}Requiring a complete code
This demo accepts digits only, requires all six, and shows errors under the boxes. Submit with three digits filled in to see the length error.
"use client";import Stack from "@mui/material/Stack";import { MuiButtonElement, MuiFormHelperTextElement } from "@piplup/rhf-adapters/mui-material";import { MuiOtpInputElement } from "@piplup/rhf-adapters/mui-one-time-password-input";import { useForm } from "react-hook-form";export default function Page() { const { control, handleSubmit } = useForm({ defaultValues: { code: "" } }); return ( <form noValidate onSubmit={handleSubmit((values) => alert(JSON.stringify(values, null, 2)))} > <Stack direction="column" spacing={1}> <MuiOtpInputElement control={control} name="code" length={6} // Ignore anything that isn't a digit, including pasted text. validateChar={(character) => /^\d$/.test(character)} required // A partly filled code is not empty, so `required` alone lets it through. minLength={6} messages={{ required: "Enter the code we sent you", minLength: "Enter all 6 digits", }} /> {/* The OTP input has no helper text, so render the error message here. */} <MuiFormHelperTextElement control={control} name="code"> We sent a 6-digit code to your email </MuiFormHelperTextElement> <div> <MuiButtonElement control={control} variant="contained" type="submit"> Verify </MuiButtonElement> </div> </Stack> </form> );}Three things make that work:
minLengthequal tolength. The value is just the characters entered so far, so"482"is not empty and passesrequired.minLength={6}rejects it. The default message is "Please lengthen this text to 6 characters or more", so setmessages.minLength.validateChar. AMuiOtpInputprop that refuses characters as they are typed or pasted. It does not check values set throughdefaultValuesorsetValue; addpattern={/^\d+$/}if those can contain other characters.- A separate helper text.
MuiOtpInputhas no helper text, and the element ignores thehelperTextprop. Errors only turn the boxes red. To show the message, renderMuiFormHelperTextElementwith the samename. It shows its children normally and the error message while the field is invalid.
How it works
Value. The form value is passed to MuiOtpInput as value, and every change stores the full code string. MuiOtpInput only shows the first length characters, but a longer value set from code is stored as is. onComplete is passed through and fires when the last box is filled.
Errors. While the field is invalid, each box gets error. If you pass TextFieldsProps (an object or a function of the box index), its props are kept and error is added on top.
Blur. The field is marked as touched only when focus leaves the whole group, not when it moves from one box to the next.
Focus. React Hook Form's ref is attached to the first box, so setFocus("code") and focus-on-error move focus there. A ref on the element goes to the MuiOtpInput root Box.
Props
Prop
Type