shadcn.io is not affiliated with official shadcn/ui
Phone Input with Country Code Form Block for Ark UI
A national-number field joined to a country menu that formats the digits for the chosen country as you type, checks the count per country and shows how the number would be stored.
Installation
Overview
Take a phone number without a format lecture, with this phone input form for React with Ark UI. A compact header sits over a hairline frame with a plus mark on each corner: a field band and a "How it is stored" band. The field is a Select of six countries, each with a two-letter tile and its dial code, joined to an Input for the national number, which formats as you type for the chosen country ("(415) 555-0132", "07700 900123") and keeps the caret with its digits. A quiet line under it states the country's rule ("A UK mobile has 11 digits with the 0"); leaving the field or pressing Save checks the count and says what is missing, then puts focus back in the field. Pasting a number that starts with a plus and a dial code switches the country to match. Under it a list shows the international form, the digits only (E.164) and the country. It's built from Select, Input, Label, Shine Button and Guides, with a CSS entrance only. For a callback number, a delivery contact, a profile or any account that keeps a phone number.
FAQ
How do I add or change a country?
Each country is one entry with its two-letter code, its dial code, the national pattern and the grouping of the international form (intl), where # stands for a digit, the fewest and most digits, the trunk digit a national number starts with and an international one drops, a placeholder and the rule in a sentence. Add an entry and put it in COUNTRIES; the menu, the formatting, the checks and the stored form all read from it. The numbers shown are in ranges set aside for fiction.
How does it format while I type, and what does pasting do?
The field keeps only digits, lays them into the country's pattern and shows a separator only once a digit follows it, so nothing dangles. After each change the caret goes back to the same digit, so editing in the middle works, and backspacing over a separator removes the digit before it. Pasting a number that begins with a plus and a dial code (+44 7700 900123) picks that country and fills the national digits, adding the trunk 0 where the country uses one. Changing the country keeps the digits and reformats them.
When is the number checked, and is that real validation?
The count is checked when you leave the field or press Save, and then again as you type. The check is the country's digit count and, where there is one, the leading trunk digit. That is a first line, not a validator: it cannot know a number is in service or assigned. For a real app, normalise and validate on the server with a phone library such as libphonenumber, and confirm ownership with a code.
What does the How it is stored band show, and is a code sent?
It shows what would be kept: the international form for people, the same number as digits with a plus (the E.164 form that dialling APIs expect, without the trunk 0) and the country. It stays blank until the count is right. Nothing is saved or verified, and no code is sent: the status line says so. Verifying a number is its own step, with its own screen.
How is it named, and does it work in a right-to-left page?
The number has a real label and is described by its rule; the country menu is named Country code. The input is type="tel" with inputmode="tel" and autocomplete="tel-national", so phones show a dialling keypad and browsers can fill it, and it stays left-to-right inside a right-to-left page, as phone numbers do. The closed menu shows the tile and the dial code; each row in the open list also names the country.
How do I connect it to react-hook-form or TanStack Form?
Keep the country code and the national digits as two values, or the stored E.164 string as one. With react-hook-form, use Controller for the number and for the country, move the digit-count rule into a resolver and use mode: "onBlur" for the same timing; shouldFocusError puts focus on the number after a refused submit. With TanStack Form, validate the number with onBlur and onChange validators and read the errors for the line under the field.