← All posts

Tutorial · September 26, 2026 · 5 min read

How to add a phone number input with country codes in React

To add a phone number input with country codes in React, install ReactFrame's free Phone Input with npx shadcn@latest add @reactframe/phone-input and render it in your form. It gives a searchable country menu, formats digits per country as people type, and submits one E.164 value such as +905321234567 for your server to validate.

Phone numbers are one of the most mistyped fields on any form. People leave out the country code, add a leading 0, paste numbers with spaces and dashes, or type one digit too few. A good phone input fixes most of that while they type and hands your backend one clean format.

This tutorial uses ReactFrame's free Phone Input element: a country menu with flags and calling codes, formatting per country, paste detection and an E.164 value.

1. Install

npx shadcn@latest add @reactframe/phone-input

It installs into components/phone-input.tsx with motion, clsx and tailwind-merge. There's no phone library underneath, so it adds very little to your bundle.

2. Drop it into a form

import { PhoneInput } from "@/components/phone-input";

export function ContactForm() {
  return (
    <form action="/api/contact" method="post" className="flex flex-col gap-4">
      <PhoneInput
        label="Phone number"
        name="phone"
        defaultCountry="TR"
        preferredCountries={["TR", "US", "GB"]}
        helperText="We'll text you a confirmation code"
      />
      <button type="submit">Send</button>
    </form>
  );
}

name="phone" adds a hidden input, so a plain form post receives phone=+905321234567 with no JavaScript on your side.

3. What people see while they type

  • Formatting per country. Digits fall into the local layout: 532 123 45 67 in Türkiye, (415) 555-0123 in the US, 7911 123456 in the UK.
  • Leading 0 dropped. Typing 0532… keeps 532…, because the trunk 0 isn't part of an international number.
  • Paste detection. Pasting +44 7911 123456 switches the country to the United Kingdom by its calling code.
  • Searchable menu. The country menu matches names, ISO codes and calling codes, so typing +49 finds Germany.
  • A length check. A check mark appears when the number has a valid length for the country, and leaving the field with too few digits shows "Enter a valid phone number".

4. Read the value

const [phone, setPhone] = React.useState("");
const [valid, setValid] = React.useState(false);

<PhoneInput
  value={phone}
  onValueChange={(value, meta) => {
    setPhone(value);          // "+905321234567"
    setValid(meta.isValid);   // length is right for the country
  }}
/>

The value is E.164, the ITU's international numbering format: a plus, the calling code and the national number, no spaces. It's the format Twilio, WhatsApp, Vonage and most SMS and calling APIs expect, and it's easy to store and compare.

5. Validate on the server

The built-in check only looks at the number's length, which catches most typos. It can't tell whether a number exists or is a mobile line. For that, validate on the server:

  • Format and type: libphonenumber-js (isValidPhoneNumber, getNumberType) knows every country's number plan.
  • Ownership: send a one-time code by SMS and ask for it back. ReactFrame's Input OTP is made for that step.

Common mistakes

  • Storing the formatted string. Store E.164; format for display only.
  • One country for everyone. Set defaultCountry from your audience (or the visitor's locale) and pin your top markets with preferredCountries.
  • Blocking the form on the length check. Treat it as a hint and let your server decide.

Phone Input shares its look with the other form elements: Credit Card Input, Currency Input, Time Picker and Form Field. All of them are free in the UI Elements kit.

Ahmet Loca

Ahmet Loca · Product designer

Hi, I'm Ahmet. I have over four years of experience creating intuitive, user-focused designs for digital products, and ReactFrame is where that work becomes components you can use in your own.

github.comx.comAbout ReactFrame