kesp-ui
npm ↗
ComponentValidation Ready

Phone Input

A production-ready Indian phone number input with automatic formatting, real-time validation, WhatsApp verification toggle, and visual feedback. Perfect for authentication flows, contact forms, and user registration.

Installation

npx kesp-ui@latest add phone-input

Or specify a custom path: npx kesp-ui@latest add phone-input -p src/components/ui

Preview

Interactive
Basic Phone Input
+91
With WhatsApp Verification
+91
Controlled Mode
+91
Error State
+91
Disabled State
+91

Usage

Basic Usage
import PhoneInput from "@/components/ui/phone-input"

function RegistrationForm() {
  const [phone, setPhone] = useState<string>("")

  const handleSubmit = () => {
    console.log("Phone number:", phone)
    registerUser({ phone })
  }

  return (
    <PhoneInput
      value={phone}
      onChange={setPhone}
    />
  )
}
With WhatsApp Verification
import PhoneInput from "@/components/ui/phone-input"

function PhoneVerification() {
  const [phone, setPhone] = useState<string>("")
  const [useWhatsApp, setUseWhatsApp] = useState<boolean>(false)

  const handleVerify = async () => {
    const method = useWhatsApp ? "whatsapp" : "sms"
    await sendOTP(phone, method)
  }

  return (
    <div>
      <PhoneInput
        value={phone}
        onChange={setPhone}
        enableWhatsApp
        whatsAppEnabled={useWhatsApp}
        onWhatsAppToggle={setUseWhatsApp}
      />
      <button onClick={handleVerify}>
        Send OTP via {useWhatsApp ? "WhatsApp" : "SMS"}
      </button>
    </div>
  )
}
With Server-Side Validation
import PhoneInput from "@/components/ui/phone-input"

function SignupForm() {
  const [phone, setPhone] = useState<string>("")
  const [error, setError] = useState<string>("")

  const validatePhone = async (value: string) => {
    if (value.length !== 10) return
    try {
      const response = await fetch("/api/check-phone", {
        method: "POST",
        body: JSON.stringify({ phone: value })
      })
      const data = await response.json()
      if (data.exists) {
        setError("This phone number is already registered")
      } else {
        setError("")
      }
    } catch (err) {
      setError("Unable to validate phone number")
    }
  }

  return (
    <PhoneInput
      value={phone}
      onChange={(value: string) => {
        setPhone(value)
        validatePhone(value)
      }}
      error={error}
    />
  )
}
Uncontrolled Mode
import PhoneInput from "@/components/ui/phone-input"

function QuickContactForm() {
  const phoneRef = useRef<HTMLInputElement>(null)

  const handleSubmit = () => {
    const phoneValue = phoneRef.current?.value
    console.log("Phone:", phoneValue)
  }

  return (
    <PhoneInput
      ref={phoneRef}
      placeholder="Enter your phone"
    />
  )
}

Key Features

Automatic Formatting

Automatically formats Indian phone numbers with proper spacing (XXXXX XXXXX). Handles paste operations and filters non-numeric characters seamlessly.

Real-Time Validation

Built-in validation for Indian phone numbers (must start with 6, 7, 8, or 9 and be exactly 10 digits). Shows clear error messages and visual feedback.

WhatsApp Verification

Optional WhatsApp toggle for alternative verification methods. Only enabled when phone number is valid. Includes animated toggle switch with clear visual states.

Visual Feedback

Dynamic border colors and icons show validation status. Green checkmark for valid numbers, red alert for errors, and blue highlight on focus. Smooth animations for state transitions.

Behavior Details

The phone input provides an intuitive user experience:

  • Input Formatting: Numbers are automatically formatted as you type. The format is XXXXX XXXXX with a space after the 5th digit for readability.
  • Validation Rules: Phone numbers must be exactly 10 digits and start with 6, 7, 8, or 9 (Indian mobile number format). Validation triggers on blur after user interaction.
  • Paste Support: Pasting phone numbers works seamlessly. Non-numeric characters are automatically filtered out, and validation is triggered immediately.
  • WhatsApp Toggle: The WhatsApp verification option only becomes available when the phone number is valid. Clicking toggles between SMS and WhatsApp verification methods.

The +91 country code prefix is fixed for Indian phone numbers and not editable by users

Props

classNameOptional

Additional CSS classes on the wrapper

stringdefault: ""
valueOptional

Controlled value (10 raw digits). Omit for uncontrolled mode

stringdefault: undefined
onChangeOptional

Called with raw 10-digit string on every change

(value: string) => voiddefault: undefined
enableWhatsAppOptional

Show WhatsApp verification toggle below the input

booleandefault: false
whatsAppEnabledOptional

Controlled WhatsApp toggle state

booleandefault: undefined
onWhatsAppToggleOptional

Called when WhatsApp toggle is clicked

(enabled: boolean) => voiddefault: undefined
errorOptional

External error message to display

stringdefault: undefined
disabledOptional

Disable the input and WhatsApp toggle

booleandefault: false
placeholderOptional

Placeholder text for the input field

stringdefault: "98765 43210"

Common Patterns

User Registration

Collect and validate phone numbers during user signup.

<PhoneInput
  value={phone}
  onChange={setPhone}
  error={serverError}
  placeholder="Enter your mobile number"
/>

OTP Verification Flow

Combine with OTP input for complete phone verification.

const [phone, setPhone] = useState<string>("")
const [useWhatsApp, setUseWhatsApp] = useState<boolean>(false)
const [showOTP, setShowOTP] = useState<boolean>(false)

<PhoneInput
  value={phone}
  onChange={setPhone}
  enableWhatsApp
  whatsAppEnabled={useWhatsApp}
  onWhatsAppToggle={setUseWhatsApp}
/>

<button
  onClick={async () => {
    await sendOTP(phone, useWhatsApp ? "whatsapp" : "sms")
    setShowOTP(true)
  }}
  disabled={phone.length !== 10}
>
  Send OTP
</button>

{showOTP && <OtpInput onComplete={verifyOTP} />}

Contact Form

Use in contact forms with optional phone number collection.

interface FormData {
  name: string
  email: string
  phone: string
}

const [formData, setFormData] = useState<FormData>({
  name: "",
  email: "",
  phone: ""
})

<PhoneInput
  value={formData.phone}
  onChange={(phone: string) => setFormData({ ...formData, phone })}
  placeholder="Phone (optional)"
/>

Profile Update

Allow users to update their phone number with re-verification.

const [phone, setPhone] = useState<string>(user.phone)
const [hasChanged, setHasChanged] = useState<boolean>(false)

<PhoneInput
  value={phone}
  onChange={(value: string) => {
    setPhone(value)
    setHasChanged(value !== user.phone)
  }}
/>

{hasChanged && phone.length === 10 && (
  <button onClick={() => verifyNewPhone(phone)}>
    Verify new number
  </button>
)}

CLI Reference

Install component
npx kesp-ui@latest add phone-input
Custom path
npx kesp-ui@latest add phone-input -p src/components/ui
List components
npx kesp-ui@latest list
Check version
npx kesp-ui --version
Help
npx kesp-ui --help