{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "phone-input",
  "title": "Phone Input",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "A native dialing-code selector paired with a telephone field that preserves the user’s formatting.",
  "registryDependencies": [
    "utils",
    "https://ui.ballmac.com/r/i18n.json"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/phone-input.tsx",
      "content": "// Ballmac UI: Phone Input. https://ui.ballmac.com/components/phone-input\n\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"@/lib/utils\"\nimport { useMessages } from \"@/lib/ballmac/i18n\"\n\ntype PhoneCountry = { code: string; label: string }\ntype PhoneInputProps = Omit<\n  React.ComponentProps<\"input\">,\n  \"type\" | \"value\" | \"defaultValue\" | \"onChange\"\n> & {\n  /** National number, controlled by the parent. Formatting is preserved. */\n  value?: string\n  /** Initial national number when uncontrolled. */\n  defaultValue?: string\n  /** Called with the edited national number. */\n  onValueChange?: (value: string) => void\n  /** Controlled international dialing prefix. */\n  countryCode?: string\n  /** Initial dialing prefix when uncontrolled. */\n  defaultCountryCode?: string\n  /** Called when the dialing prefix changes. */\n  onCountryCodeChange?: (code: string) => void\n  /** Dialing prefixes available in the menu. */\n  countries?: PhoneCountry[]\n  /** Accessible name of the number field. */\n  label?: string\n  /** Name of the separate country-code form field. */\n  countryCodeName?: string\n}\nconst defaultCountries: PhoneCountry[] = [\n  { code: \"+1\", label: \"+1 United States\" },\n  { code: \"+44\", label: \"+44 United Kingdom\" },\n  { code: \"+91\", label: \"+91 India\" },\n  { code: \"+49\", label: \"+49 Germany\" },\n  { code: \"+61\", label: \"+61 Australia\" },\n]\nfunction PhoneInput({\n  value,\n  defaultValue = \"\",\n  onValueChange,\n  countryCode,\n  defaultCountryCode = \"+1\",\n  onCountryCodeChange,\n  countries = defaultCountries,\n  label,\n  countryCodeName,\n  className,\n  disabled,\n  ...props\n}: PhoneInputProps) {\n  const msg = useMessages()\n  label ??= msg(\"phone-input.label\", \"Phone number\")\n  const [internal, setInternal] = React.useState(defaultValue)\n  const [internalCode, setInternalCode] = React.useState(defaultCountryCode)\n  const current = value ?? internal\n  const code = countryCode ?? internalCode\n  return (\n    <div\n      data-slot=\"phone-input\"\n      className={cn(\n        \"flex h-9 w-full min-w-0 items-center rounded-md border border-input bg-background shadow-xs transition-[border-color,box-shadow] duration-150 motion-reduce:transition-none focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50\",\n        className,\n      )}\n    >\n      <select\n        data-slot=\"phone-input-country\"\n        aria-label={msg(\"phone-input.countryDialingCode\", \"Country dialing code\")}\n        name={countryCodeName}\n        disabled={disabled}\n        value={code}\n        onChange={(event) => {\n          if (countryCode === undefined) setInternalCode(event.target.value)\n          onCountryCodeChange?.(event.target.value)\n        }}\n        className=\"h-full max-w-24 shrink-0 rounded-s-md border-e border-input bg-transparent px-2 text-sm text-foreground outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:opacity-50\"\n      >\n        {countries.map((country) => (\n          <option key={country.code} value={country.code}>\n            {country.label}\n          </option>\n        ))}\n      </select>\n      <input\n        data-slot=\"phone-input-field\"\n        type=\"tel\"\n        inputMode=\"tel\"\n        autoComplete=\"tel-national\"\n        aria-label={label}\n        disabled={disabled}\n        value={current}\n        onChange={(event) => {\n          if (value === undefined) setInternal(event.currentTarget.value)\n          onValueChange?.(event.currentTarget.value)\n        }}\n        className=\"h-full min-w-0 flex-1 bg-transparent px-3 text-sm text-foreground outline-none placeholder:text-muted-foreground disabled:opacity-50\"\n        {...props}\n      />\n    </div>\n  )\n}\nexport { PhoneInput, type PhoneInputProps, type PhoneCountry }\n",
      "type": "registry:ui",
      "target": "@components/ballmac/phone-input.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "phone",
      "telephone",
      "country"
    ],
    "version": "1.0.0",
    "updated": "2026-09-30",
    "ai": {
      "summary": "A native dialing-code selector paired with a telephone field that preserves the user’s formatting.",
      "whenToUse": [
        "Collect a contact number with a dialing prefix",
        "Edit a national number without forced formatting"
      ],
      "whenNotToUse": [
        "Use input type tel when a country selector is unnecessary"
      ],
      "composesWith": [
        "input"
      ],
      "a11y": [
        {
          "keys": "Arrow Up / Down",
          "action": "Changes the native dialing-code selection"
        },
        {
          "keys": "Tab",
          "action": "Moves to the telephone field"
        }
      ],
      "customization": [
        "countries, countryCodeName",
        "value / defaultValue and onValueChange"
      ]
    },
    "examples": [
      "phone-input-demo",
      "phone-input-states"
    ],
    "url": "https://ui.ballmac.com/components/phone-input"
  },
  "categories": [
    "forms"
  ],
  "type": "registry:ui"
}