OTP
The Otp
component allows you to implement a One-Time Password (OTP) verification UI. With the customUIRender
prop, you can fully customize the look and behavior of the OTP interface to match your project's needs.
Installation Method
You can use the following command to install the extension with the latest plugins:
npx @akinon/projectzero@latest --plugins
Props
customUIRender
React.ReactNode
Optional
A render function to override the default OTP interface. Provides access to UI and control handlers
submitAction
SubmitHandler<{ [key: string]: any }>
Yes
A submit handler function triggered when OTP form is submitted.
data
{ [key: string]: any }
Yes
Data object containing required fields like phone number. OTP code will be appended here before submission
CustomUIRender Parameters
closeHandler
() => void
Closes the popup manually.
resendHandler
() => void
Triggers OTP resend functionality.
onSubmit
(event: FormEvent<HTMLFormElement>) => Promise<void>
Form submit function that wraps validation and calls submitAction.
otp
string
Current OTP value in the input field.
setOtp
(otp: string) => void
Updates the OTP input value.
hasError
boolean
Whether the current OTP input has a validation error.
error
string
Error message for invalid OTP attempts.
canResend
boolean
Indicates whether the resend option is enabled.
time
number
Countdown in seconds for the resend option.
codeLength
number
Expected number of digits in the OTP input.
setHasError
(hasError: boolean) => void
Allows toggling of error state manually.
Usage Example
Default Usage
import PluginModule, { Component } from '@akinon/next/components/plugin-module';
<PluginModule
component={Component.Otp}
props={{
data: getValues(),
submitAction: registerHandler
}}
/>
Customizing OTP
import PluginModule, { Component } from '@akinon/next/components/plugin-module';
<PluginModule
component={Component.Otp}
props={{
data: getValues(),
submitAction: registerHandler,
customUIRender: ({
closeHandler,
resendHandler,
onSubmit,
otp,
setOtp,
hasError,
error,
canResend,
time,
codeLength,
setHasError
}) => {
return (
<div className="fixed left-0 top-0 z-50 flex h-screen w-screen items-end md:items-center md:justify-center md:bg-black/10">
<div className="h-[calc(100vh-48px)] w-screen flex md:h-auto md:max-w-lg flex-col items-center rounded-sm bg-white p-8 shadow-xl">
<div className="w-full flex items-center justify-end">
<div className="cursor-pointer" onClick={closeHandler}>
<svg
width="14"
height="14"
viewBox="0 0 14 14"
xmlns="http://www.w3.org/2000/svg"
>
<g fill="#000" fillRule="nonzero">
<path d="M.684 14A.684.684 0 0 1 .2 12.833L12.833.2a.684.684 0 1 1 .967.967L1.167 13.8a.682.682 0 0 1-.483.2z" />
<path d="M13.316 14a.682.682 0 0 1-.483-.2L.2 1.167A.684.684 0 0 1 1.167.2L13.8 12.833A.684.684 0 0 1 13.316 14z" />
</g>
</svg>
</div>
</div>
<div className="flex flex-col items-center px-14 mt-5">
<div className="text-2xl font-medium">OTP Verification</div>
<div className="mt-2.5 text-center text-gray-700">
{`Please enter the ${codeLength}-digit sms code sent to your registered number and email address`}
</div>
</div>
<form
onSubmit={onSubmit}
className="flex flex-col items-center w-full"
>
<OtpInput
value={otp}
onChange={(otp) => {
setOtp(otp);
setHasError(false);
}}
numInputs={codeLength}
containerStyle="mt-12 gap-2 flex-wrap"
inputStyle={`h-12 w-8 md:h-16 md:w-12 rounded-md border border-gray-600 text-center text-lg ${hasError ? 'border-error' : ''}`}
renderInput={(props) => <input {...props} />}
skipDefaultStyles={true}
/>
{error && <p className="text-xs text-error mt-2">{error}</p>}
<Button
type="submit"
className="mt-5 h-auto w-full py-4 text-lg font-medium uppercase"
>
Verify
</Button>
</form>
<div className="mt-6 flex flex-col items-center">
<span className="text-gray-700">I didn’t receive a code</span>
<div
className={`font-medium underline cursor-pointer ${!canResend ? 'cursor-not-allowed text-gray-700' : ''}`}
onClick={resendHandler}
>
RESEND
</div>
</div>
</div>
</div>
);
}
}}
/>;
Last updated
Was this helpful?