# PhoneInput

> An international phone field: `react-phone-number-input` with Max's `Input` and a searchable country picker that shows flags.

## Facts

- **Product**: Max
- **Family**: Forms
- **Global**: `window.DigitalCrew.PhoneInput`
- **Source**: `max-agent: src/components/ui/phone-input.tsx`
- **Import in the app**: `import { PhoneInput } from "@/components/ui/phone-input";`
- **Live preview**: /design/components/phone-input/preview.html
- **Page**: /design/components/phone-input

## Guidelines

**Use it for** phone numbers people type themselves, such as the phone field on a public booking page.

**What you provide**: any `react-phone-number-input` prop, for example `defaultCountry`, `international`, `countryCallingCodeEditable`, `placeholder`, `disabled` or `id`. Also:
- `value`: an E.164 string such as `+33612345678`.
- `onChange(value)`: called with an empty string when the field is cleared.
- `className`: applied to the root, which is `flex`.

`smartCaret` is off. The booking form uses `international`, `defaultCountry` and `countryCallingCodeEditable={false}`.

**Anatomy**:
- The country button is an outline [`Button`](/design/components/button.md) joined to the input: `rounded-s-lg rounded-e-none border-r-0 px-3`, with a flag in an `h-4 w-6 rounded-sm bg-foreground/20` frame and a `ChevronsUpDown` icon.
- The input is Max's [`Input`](/design/components/input.md) with `rounded-e-lg rounded-s-none`.
- The picker is a 300px-wide popover holding a [`Command`](/design/components/command.md) list: search reads "Search country...", the list is an `h-72` scroll area, and each row shows the flag, the country name, the calling code in `text-foreground/50`, and a check on the selected country.

**Behaviour**: the popover is modal and closes when a country is picked. The number is formatted as you type.

**Don't** store the formatted display string. Store the E.164 value from `onChange`.

## API

```ts
declare const PhoneInput: any;
export { PhoneInput };
```

## Example

```html
<div id="root" class="p-6"></div>
<script>
(function () {
  var h = React.createElement, DC = window.DigitalCrew, I = DC.Icons;
  function App() {
    var a = React.useState("+33612345678"), phone = a[0], setPhone = a[1];
    var b = React.useState(""), phone2 = b[0], setPhone2 = b[1];
    return h("div", { className: "grid max-w-sm gap-4" },
      h("div", { className: "space-y-1.5" },
        h(DC.Label, { htmlFor: "booking-phone" }, "Phone"),
        h(DC.PhoneInput, { id: "booking-phone", international: true, defaultCountry: "FR", countryCallingCodeEditable: false, value: phone, onChange: setPhone })),
      h("div", { className: "space-y-1.5" },
        h(DC.Label, { htmlFor: "booking-phone-2" }, "Mobile (optional)"),
        h(DC.PhoneInput, { id: "booking-phone-2", defaultCountry: "DE", placeholder: "Enter a phone number", value: phone2, onChange: setPhone2 }),
        h("p", { className: "text-xs text-muted-foreground" }, "Value is stored as E.164, for example +4915112345678.")));
  }
  ReactDOM.createRoot(document.getElementById("root")).render(h(DC.TooltipProvider, { delayDuration: 80 }, h(App)));
})();
</script>
```

## More in Forms

- [Calendar](/design/components/calendar.md): A month grid (react-day-picker 10) in the app's tokens: today and the selection in `primary`, outside days muted.
- [Checkbox](/design/components/checkbox.md): A 16px square check for independent on/off choices and row selection; the box fills in 150ms, then the tick draws in over 350ms (`.t-check`).
- [DateTimePicker](/design/components/date-time-picker.md): A date-and-time field in the app's own widget, instead of the browser's `datetime-local`; works in ISO strings.
- [Form](/design/components/form.md): Form fields wired to react-hook-form: each field gets a label, a control, an optional hint and an error message, with ids and ARIA linked for you.
- [Input](/design/components/input.md): The single-line text field: 36px tall, `input` border, `radius-md`, transparent over its ground (dark themes fill it with `input` at 30%).
- [Label](/design/components/label.md): The accessible field label (Radix Label): 14px medium, `leading-none`, 8px gap for an inline icon or `HelpTooltip`.
- [RadioGroup](/design/components/radio-group.md): One choice from a short, visible list (Radix RadioGroup): 16px rings in `primary`, 10px dot.
- [SecretInput](/design/components/secret-input.md): A field for API keys and tokens: masked by default with a reveal toggle, monospace, opted out of autofill.
- [Select](/design/components/select.md): A native-feeling single choice from a list (Radix Select): 36px trigger (`size="sm"`: 32px) with a chevron; the list opens in 250ms from 97% (`.t-dropdown`).
- [Slider](/design/components/slider.md): A Radix slider for picking a number, or a range with two thumbs, on a continuous scale.
- [Switch](/design/components/switch.md): The on/off control for settings that apply immediately (Radix Switch): a 32 × 18px pill, `input` track off, `primary` on, 16px thumb with a double-bounce (`.t-toggle`, 350ms thumb, 150ms track).
- [Textarea](/design/components/textarea.md): The multi-line field; it grows with its content (`field-sizing: content`) from a 64px minimum.
- [TimezoneSelector](/design/components/timezone-selector.md): A searchable combobox (a `Popover` holding a `Command` list) over every IANA time zone the browser knows.
- [TypedOptionPicker](/design/components/typed-option-picker.md): A searchable, grouped picker for long option lists (Popover + Command), in single and multi versions.
