Phone Input

A country-code Select joined to a national-number Input (via Join), with a lightweight generic digit-grouping formatter.

Colors

Sizes

Controlled

E.164: (empty)

Using Phone Input

Silica ships one design system through three paths. They share a class vocabulary but are not interchangeable — pick the one that matches what you are building.

Plain HTML — CSS classes

The Tailwind v4 plugin. Works in any framework or none — Rails, Django, PHP, Go, a static file. This path ships no JavaScript, so Phone Input is styled but inert: its behavior comes from phone-input. For that behavior with no framework, use the node-tree path below.

/* in your CSS */
@import "tailwindcss";
@plugin "@wizeworks/silicaui";

Root class phone-input-country, with 0 modifiers:

  • .phone-input-country

React

Typed components over those same classes, with behavior and accessibility from Base UI.

npm i @wizeworks/silicaui-react
import { PhoneInput } from "@wizeworks/silicaui-react";

Props

PropTypeRequiredDescription
valuestringnoControlled national number (digits, or digits with formatting — either is fine).
defaultValuestringnoUncontrolled initial national number.
onValueChange(national: string, e164: string) => voidnoFires on every keystroke with the raw national digits and the full E.164 string.
countrystringnoControlled selected country (ISO 3166-1 alpha-2).
defaultCountrystringnoUncontrolled initial country. Default "US".
onCountryChange(iso2: string) => voidnoFires when the country picker selection changes.
countriesCountry[]noOverride/extend the built-in country list.
colorPhoneInputColornoAccent color; maps to input-<color>/select-<color> (border + focus ring).
sizePhoneInputSizenoDefault md. Matches same-size Input/Select heights.
disabledbooleanno—
placeholderstringno—
namestringnoField name for form submission (submits the national digits).
idstringno—
classNamestringno—
"aria-label"stringno—

Source of the demo above

The exact file that renders the examples above, so it can never drift from them. It imports a few of this site’s own layout helpers (../lib/…), so read it for the component calls rather than copying it whole.

Show source
import { useState } from "react";
import { PhoneInput } from "@wizeworks/silicaui-react";
import { Section, Stack } from "../lib/Section";
import { SIZES } from "../lib/data";

export function PhoneInputDemo() {
    const [national, setNational] = useState("");
    const [e164, setE164] = useState("");

    return (
        <>
            <Section title="Colors">
                <Stack className="max-w-sm">
                    <PhoneInput />
                    <PhoneInput color="primary" defaultCountry="GB" defaultValue="7911123456" />
                    <PhoneInput disabled defaultCountry="DE" defaultValue="15123456789" />
                </Stack>
            </Section>

            <Section title="Sizes">
                <Stack className="max-w-sm">
                    {SIZES.map((size) => (
                        <PhoneInput key={size} size={size} />
                    ))}
                </Stack>
            </Section>

            <Section title="Controlled">
                <Stack className="max-w-sm">
                    <PhoneInput
                        value={national}
                        onValueChange={(nat, e164) => {
                            setNational(nat);
                            setE164(e164);
                        }}
                    />
                    <p className="text-xs opacity-60">E.164: {e164 || "(empty)"}</p>
                </Stack>
            </Section>
        </>
    );
}

Vanilla — node tree to HTML

phone-input — a country <select> (options carry data-dial) joined with a digits input; the country list is plain static data, ported verbatim (no React-only mechanism was involved in the original). Build a node tree, project it with toHtml(), and let the zero-dependency runtime hydrate it. This is the path for generated or user-authored documents — a site builder, CMS output, a static export.

npm i @wizeworks/silicaui-html @wizeworks/silicaui-behaviors
import { atom, toHtml } from "@wizeworks/silicaui-html";

const node = atom("PhoneInput", "phone-input-country", { /* props */ });
const markup = toHtml(node);

Styling on this path is the class string in the second argument — the same classes as the Plain HTML section above. There is no color prop here; write "phone-input-country phone-input-country-primary" rather than passing a colour as a prop.

Takes children
no
Hydrated by
phone-input

Load @wizeworks/silicaui-behaviors on the page or this markup renders correctly and does nothing.

The full API for Phone Input, on every path, is available through the Silica MCP server.