Skip to Content
WebComponentAuthVerify OTP

🔐 OtpInput

The OtpInput component handles OTP verification after phone login.
It uses the OtpInput UI from @zezosoft/zezo-ott-react-ui-kit and verifies the OTP with the verifyOtp API.


✨ Features

  • Verifies 4-digit OTP from the user
  • Validates OTP format before submitting
  • Pulls phone and hash from the query string
  • Uses React Query for API mutation
  • Shows success/error toasts
  • Automatically redirects to / on success
  • Includes back navigation button
  • Auto-fails gracefully if query params are missing

🔌 Props

PropTypeDescriptionOptionalDefault
countryCodestringCountry dialing code (e.g. +91)No
phoneNumberstringPhone number to show on the screenNo
onSubmit(otp: string) => voidCallback to submit the OTPYes
isLoadingbooleanShow loading spinner on submit buttonYesfalse
goBack() => voidCallback to handle back buttonYes
errorstringDisplay error message below OTP fieldYes
otpLengthnumberOTP length to be accepted (e.g., 4 or 6)Yes4
resetTimenumberCountdown time in seconds to re-request OTPYes120
titlestringHeading text to show above the inputYes”Enter OTP”

📦 Usage

"use client"; /* eslint-disable @typescript-eslint/no-explicit-any */ import { OtpInput as ZezoOtpInput } from "@zezosoft/zezo-ott-react-ui-kit"; import { useMutation } from "@tanstack/react-query"; import { useRouter, useSearchParams } from "next/navigation"; import React, { useEffect, useRef, useState } from "react"; import { zezoClient } from "@/lib/zezoClient"; const OtpInput: React.FC = () => { const router = useRouter(); const searchParams = useSearchParams(); const phone = searchParams.get("phone"); const hash = searchParams.get("hash"); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState<string | undefined>(); const hasSubmittedRef = useRef(false); useEffect(() => { if (!phone || !hash) { router.push("/login"); } }, [phone, hash, router]); const verifyOtpMutation = useMutation({ mutationKey: ["verifyOtp"], mutationFn: (payload: { phone: string; hash: string; otp: number }) => zezoClient().auth.verifyOTP(payload), onSuccess: (data) => { setIsLoading(false); hasSubmittedRef.current = false; if (data?.data === "success") { router.push("/"); } else { const errMsg = data?.data || "Failed to verify OTP"; setError(errMsg); } }, onError: (err: any) => { setIsLoading(false); hasSubmittedRef.current = false; const errMsg = err?.message || "Something went wrong"; setError(errMsg); }, }); const handleSubmit = (otp: string) => { if (hasSubmittedRef.current) return; if (otp.length !== 4 || isNaN(Number(otp))) { const errMsg = "Please enter a valid OTP"; setError(errMsg); return; } if (!phone || !hash) { return; } setError(undefined); setIsLoading(true); hasSubmittedRef.current = true; verifyOtpMutation.mutate({ phone, hash, otp: Number(otp), }); }; return ( <ZezoOtpInput title="Enter OTP" countryCode="+91" phoneNumber={phone || ""} onSubmit={handleSubmit} isLoading={isLoading || verifyOtpMutation.isPending} error={error} goBack={() => router.back()} otpLength={4} resetTime={120} /> ); }; export default OtpInput;

🖼️ UI Preview

Here’s how the verifyOtp component looks in action:

Search UI

Last updated on