---
title: "MazInputPhoneNumber"
description: "MazInputPhoneNumber is a powerful and user-friendly component that helps users enter and validate phone numbers from any country with automatic formatting and validation"
package: "maz-ui"
url: "https://maz-ui.com/components/maz-input-phone-number"
---

# MazInputPhoneNumber

> MazInputPhoneNumber is a powerful and user-friendly component that helps users enter and validate phone numbers from any country with automatic formatting and validation

- Package: `maz-ui`
- Import: `import MazInputPhoneNumber from 'maz-ui/components/MazInputPhoneNumber'`
- Nuxt: auto-imported by `@maz-ui/nuxt`, no import needed in a Nuxt app
- Web: https://maz-ui.com/components/maz-input-phone-number

> Before use it, you should install the MazUi plugin in your project, follow instructions in [Getting Started](../guide/getting-started.md)

**Tip:**

This component can be translated globally using the [MazUi](https://maz-ui.com/ecosystem/translations.md) plugin.

**Tip: ✨ What makes this component special?**

- **Smart country detection** - Automatically detects country from browser locale or IP
- **Real-time validation** - Visual feedback as you type
- **Auto-formatting** - Formats numbers according to country standards
- **Search countries** - Find countries quickly in the dropdown
- **Customizable** - Full control over appearance and behavior
- **Accessible** - Keyboard navigation and screen reader support
- **International** - Supports all countries and phone formats

## Basic Usage

The simplest way to use MazInputPhoneNumber - just add it and it works!

```vue
<script setup lang="ts">
import type { MazInputPhoneNumberData } from 'maz-ui/components/MazInputPhoneNumber'
import MazInputPhoneNumber from 'maz-ui/components/MazInputPhoneNumber'
import { ref } from 'vue'

const phoneNumber = ref<string>()
const countryCode = ref<string>()
const results = ref<MazInputPhoneNumberData>()
</script>

<template>
  <MazInputPhoneNumber
    v-model="phoneNumber"
    v-model:country-code="countryCode"
    @data="results = $event"
  />
</template>
```

## Country Management

Control which countries appear in the dropdown and their order.

```vue
<template>
  <!-- Preferred countries (moved to top, order not preserved) -->
  <MazInputPhoneNumber
    v-model="phoneNumber"
    :preferred-countries="['US', 'FR', 'GB', 'DE', 'CA']"
    placeholder="Common countries appear first"
  />

  <!-- Only specific countries -->
  <MazInputPhoneNumber
    v-model="phoneNumber"
    :only-countries="['US', 'FR', 'GB', 'DE', 'IT', 'ES']"
    placeholder="Only European + North American countries"
  />

  <!-- Ignore certain countries -->
  <MazInputPhoneNumber
    v-model="phoneNumber"
    :ignored-countries="['AF', 'AL', 'DZ']"
    placeholder="Some countries are hidden"
  />
</template>
```

## Layout Orientations

Choose how the country selector and phone input are arranged.

```vue
<template>
  <!-- Responsive layout (default) -->
  <MazInputPhoneNumber
    top-label="Responsive"
    assistive-text="Stacks on mobile, side-by-side on desktop"
    orientation="responsive"
  />

  <!-- Always side-by-side -->
  <MazInputPhoneNumber
    top-label="Always Row"
    assistive-text="Side-by-side on all screen sizes"
    orientation="row"
  />

  <!-- Always stacked -->
  <MazInputPhoneNumber
    top-label="Always Column"
    assistive-text="Stacked on all screen sizes"
    orientation="col"
  />
</template>
```

## Display Options

Customize what information is shown to users.

```vue
<template>
  <!-- Show country names instead of codes -->
  <MazInputPhoneNumber
    display-country-name
    :translations="{ countrySelect: { placeholder: 'Choose country' } }"
  />

  <!-- Show calling codes in dropdown -->
  <MazInputPhoneNumber show-code-in-list />

  <!-- Hide phone number examples -->
  <MazInputPhoneNumber :example="false" />

  <!-- Hide country flags -->
  <MazInputPhoneNumber hide-flags />

  <!-- Flags of maz-ui, no request to flagcdn.com: import { loadCountryFlag } from 'maz-ui/country-flags' -->
  <MazInputPhoneNumber :flag-src="loadCountryFlag" />

  <!-- Your own files: public/flags/fr.svg... -->
  <MazInputPhoneNumber flag-src="/flags/{code}.svg" />
</template>
```

### Flags source

By default, the flags come from the [flagcdn.com](https://flagcdn.com) CDN. The `flag-src` prop, passed to the country selector, takes:

- `loadCountryFlag` from `maz-ui/country-flags`: the flags of `@maz-ui/icons`, without any request to a third party, offline (hybrid apps with Capacitor or Cordova, PWAs);
- a URL template of your own files: `'/flags/{code}.svg'` (`{CODE}` for uppercase codes);
- your own function: `(code) => string | undefined | Promise<string | undefined>`.

Each flag is loaded only when visible, and a code without flag displays a badge. Set it once for the whole app with `defaults.global.flagSrc` of the MazUi plugin, or `mazUi.flags` of the Nuxt module (`'local'` or a URL template):

```ts
import { loadCountryFlag } from 'maz-ui/country-flags'

app.use(MazUi, { theme: { preset: mazUi }, defaults: { global: { flagSrc: loadCountryFlag } } })
```

See [MazSelectCountry](./maz-select-country.md#flags-source) for the details (bundle, Content Security Policy, PWA precache).

## Smart Country Detection

Let the component automatically detect the user's country.

```vue
<template>
  <!-- Auto-detect from browser (default behavior) -->
  <MazInputPhoneNumber :use-browser-locale="true" />

  <!-- Auto-detect from IP address -->
  <MazInputPhoneNumber fetch-country />

  <!-- Set specific default country -->
  <MazInputPhoneNumber
    :use-browser-locale="false"
    country-code="JP"
  />
</template>
```

## Phone Number Formatting

Control how phone numbers are automatically formatted as users type.

```vue
<template>
  <!-- Format on blur (default) - best UX for most cases -->
  <MazInputPhoneNumber auto-format="blur" />

  <!-- Format while typing - immediate visual feedback -->
  <MazInputPhoneNumber auto-format="typing" />

  <!-- Disable formatting - for special cases -->
  <MazInputPhoneNumber auto-format="disabled" />

  <!-- Legacy boolean support (false = disabled, true = typing) -->
  <MazInputPhoneNumber :auto-format="false" />
</template>
```

## Validation States

Control the visual validation feedback and success/error indicators.

```vue
<template>
  <!-- Hide validation indicators -->
  <MazInputPhoneNumber
    :validation-success="false"
    :validation-error="false"
  />

  <!-- Force success state -->
  <MazInputPhoneNumber success />

  <!-- Force error state -->
  <MazInputPhoneNumber error />
</template>
```

## Internationalization

Make the component speak your users' language.

```vue
<template>
  <!-- Custom translations -->
  <MazInputPhoneNumber
    :translations="{
      countrySelect: {
        placeholder: 'Select your country',
        error: 'Please choose a country',
        searchPlaceholder: 'Search countries...'
      },
      phoneInput: {
        placeholder: 'Enter phone number',
        example: 'Format: {example}'
      }
    }"
  />

  <!-- French country names -->
  <MazInputPhoneNumber country-locale="fr-FR" />

  <!-- Custom country names -->
  <MazInputPhoneNumber
    :custom-countries-list="{
      US: 'United States of America',
      GB: 'United Kingdom',
      FR: 'République Française'
    }"
  />
</template>
```

## Custom Flag Styling

Replace the default flag emojis with your own design.

```vue
<template>
  <!-- Country code badges -->
  <MazInputPhoneNumber>
    <template #selector-flag="{ countryCode }">
      <span class="country-badge">
        {{ countryCode }}
      </span>
    </template>
    <template #country-list-flag="{ countryCode }">
      <MazBadge size="sm" class="me-2">
        {{ countryCode }}
      </MazBadge>
    </template>
  </MazInputPhoneNumber>

  <!-- Custom icons -->
  <MazInputPhoneNumber>
    <template #selector-flag="{ countryCode }">
      <div class="custom-flag-icon">
        {{ countryCode?.charAt(0) }}
      </div>
    </template>
    <template #country-list-flag="{ countryCode }">
      <div class="custom-list-icon">
        {{ countryCode?.charAt(0) }}
      </div>
    </template>
  </MazInputPhoneNumber>
</template>

<style scoped>
@reference "../../.vitepress/theme/main.css";
.country-badge {
  @apply bg-primary text-primary-foreground px-2 py-1 rounded-md text-xs font-semibold;
}

.custom-flag-icon,
.custom-list-icon {
  @apply w-6 h-6 bg-linear-to-r from-blue-500 to-green-500 rounded-full flex items-center justify-center text-white text-xs font-bold;
}

.custom-list-icon {
  @apply me-2;
}
</style>
```

## Advanced Configuration

Fine-tune the component for specific use cases.

```vue
<template>
  <!-- Phone-only mode -->
  <MazInputPhoneNumber
    hide-country-select
    country-code="US"
    :translations="{
      phoneInput: {
        placeholder: 'US Phone Number'
      }
    }"
  />

  <!-- Fuzzy search -->
  <MazInputPhoneNumber :search-threshold="0.3" />

  <!-- No search -->
  <MazInputPhoneNumber :search="false" />

  <!-- Different dropdown position -->
  <MazInputPhoneNumber list-position="top-start" />
</template>
```

## Real-world Examples

See how to use the component in common scenarios.

```vue
<script setup>
import { ref } from 'vue'

const businessPhone = ref()
const businessCountry = ref()
const businessResults = ref()

const globalPhone = ref()
const mobilePhone = ref()
</script>

<template>
  <!-- Business form -->
  <div class="form-container">
    <MazInput label="Full Name" placeholder="John Doe" />
    <MazInput label="Email" type="email" placeholder="john@example.com" />
    <MazInputPhoneNumber
      v-model="businessPhone"
      v-model:country-code="businessCountry"
      label="Business Phone"
      :preferred-countries="['US', 'CA', 'GB', 'AU']"
      @data="businessResults = $event"
    />
    <MazBtn color="primary" block>Create Account</MazBtn>
  </div>

  <!-- Global support -->
  <MazInputPhoneNumber
    v-model="globalPhone"
    country-locale="es-ES"
    show-code-in-list
    :translations="{
      countrySelect: {
        placeholder: 'País',
        searchPlaceholder: 'Buscar país...'
      },
      phoneInput: {
        placeholder: 'Número de teléfono'
      }
    }"
  />

  <!-- Mobile-first -->
  <MazInputPhoneNumber
    v-model="mobilePhone"
    orientation="col"
    size="lg"
    fetch-country
    block
  />
</template>
```

## Data Handling

Understanding what data the component provides.

```vue
<script setup>
import { ref } from 'vue'

const dataPhone = ref()
const dataCountry = ref()
const phoneData = ref()

// Handle the data event
function handlePhoneData(results) {
  console.log('Phone validation results:', results)
  // results contains:
  // - isValid: boolean
  // - countryCode: string
  // - formatNational: string
  // - formatInternational: string
  // - e164: string
  // - type: 'mobile' | 'fixedLine' | etc.
  // - and more...
}
</script>

<template>
  <MazInputPhoneNumber
    v-model="dataPhone"
    v-model:country-code="dataCountry"
    @data="handlePhoneData"
  />
</template>
```

## Troubleshooting

Common issues and solutions:

### ⚠️ Auto-formatting Issues

For countries like Anguilla (AI) with multiple valid number lengths, disable auto-formatting:

```vue
<MazInputPhoneNumber auto-format="disabled" country-code="AI" />
```

### 🌐 Country Detection Not Working

Make sure to enable the right detection method:

```vue
<!-- Browser locale (default) -->
<MazInputPhoneNumber :use-browser-locale="true" />

<!-- IP-based detection (requires internet) -->
<MazInputPhoneNumber fetch-country />

<!-- Manual fallback -->
<MazInputPhoneNumber country-code="US" />
```

## Types

**Results object emitted by `@data` event:**

```ts
interface MazInputPhoneNumberData {
  isValid: boolean
  isPossible?: boolean
  countryCode?: CountryCode
  countryCallingCode?: CountryCallingCode
  nationalNumber?: NationalNumber
  type?: NumberType
  formatInternational?: string
  formatNational?: string
  uri?: string
  e164?: string
  rfc3966?: string
  possibleCountries?: CountryCode[]
  phoneNumber?: string
}
```

## MazInputPhoneNumber API

`import MazInputPhoneNumber from 'maz-ui/components/MazInputPhoneNumber'`

### Props

- `model-value` (`string | null`, `v-model`): The current value of the input field in international format (e.g. +33612345678).
- `country-code` (`CountryCode | null`, `v-model:country-code`): The selected country code (e.g. "FR").
- `id` (`string`): Unique identifier for the component.
- `placeholder` (`string`): Text displayed when the input is empty.
- `top-label` (`string`): Static label displayed above the input field. Unlike the floating label, this remains fixed.
- `label` (`string`): Label displayed above the input.
- `preferred-countries` (`CountryCode[]`): List of country codes to place first in the select list.
- `ignored-countries` (`CountryCode[]`): List of country codes to be removed from the select list.
- `only-countries` (`CountryCode[]`): List of country codes to only have the countries selected in the select list.
- `translations` (`Partial<{ countrySelect: { placeholder: string; error: string; searchPlaceholder: string; }; phoneInput: { placeholder: string; example: string; }; }>`, default: `{ countrySelect: { error: 'Choose country', placeholder: 'Country code', searchPlaceholder: 'Search the country', }, phoneInput: { placeholder: 'Phone number', example: 'Example: {example}', }, }`): Locale strings of the component The default values are the translations of the MazUiTranslations plugin.
- `list-position` (`MazPopoverPosition`, default: `"bottom-start"`): Position where the list of countries will be opened. Values: `'top'`, `'left'`, `'right'`, `'bottom'` (non exhaustive).
- `color` (`"primary" | "secondary" | "accent" | "info" | "success" | "warning" | "destructive" | "contrast" | "transparent"`, default: `"primary"`): Component color applied.
- `size` (`"xs" | "sm" | "md" | "lg" | "xl" | "mini"`, default: `"md"`): Component size applied.
- `hide-flags` (`boolean`, default: `false`): Remove flags in country list.
- `flag-src` (`MazCountryFlagSrc`, default: `undefined (flags from flagcdn.com)`): Source of the flags, instead of the flagcdn.com CDN: a URL template (`/flags/{code}.svg`, `{CODE}` for uppercase) or a function giving the image source of a code. Use `loadCountryFlag` from `maz-ui/country-flags` for the flags of `@maz-ui/icons`. Can be set for the whole app with the `defaults.global.flagSrc` option of the MazUi plugin.
- `disabled` (`boolean`, default: `false`): Make the input disabled.
- `required` (`boolean`, default: `false`): Make the input required.
- `example` (`boolean`, default: `true`): Show the phone number example.
- `search` (`boolean`, default: `true`): Disable search input in country list.
- `search-threshold` (`number`, default: `0.75`): Threshold of the search input in country list where 1 is a perfect match and 0 is a match with any character.
- `use-browser-locale` (`boolean`, default: `true`): If true, the browser locale will be used.
- `fetch-country` (`boolean`, default: `false`): The component will make a request (https://ipwho.is) to get the location of the user and use it to set the default country code.
- `hide-country-select` (`boolean`, default: `false`): Hide the country selector.
- `show-code-in-list` (`boolean`, default: `false`): Show country calling code in the country list.
- `custom-countries-list` (`Record<CountryCode, string>`): Replace country names.
- `auto-format` (`false | "disabled" | "blur" | "typing"`, default: `"blur"`): Disabled auto-format when phone is valid.
- `country-locale` (`string`): Locale of country list.
- `validation-error` (`boolean`, default: `true`): Disable validation error UI.
- `validation-success` (`boolean`, default: `true`): Disable validation success UI.
- `success` (`boolean`, default: `false`): Add success UI.
- `error` (`boolean`, default: `false`): Add error UI.
- `warning` (`boolean`, default: `false`): Add warning UI.
- `display-country-name` (`boolean`, default: `false`): Will replace the calling code by the country name in the country selector.
- `block` (`boolean`, default: `false`): The input will be displayed in full width.
- `orientation` (`"row" | "col" | "responsive"`, default: `"responsive"`): Orientation of the inputs in the component.
- `country-select-attributes` (`Record<string, unknown>`, default: `{ name: "country", autocomplete: "off", style: { width: "14rem", }, }`): Meta attributes of the country input.
- `phone-input-attributes` (`(Record<string, unknown> & { name: string; inputmode: "none" | "text" | "search" | "url" | "email" | "tel" | "numeric" | "decimal" | undefined; autocomplete: string; })`, default: `{ name: "phone", autocomplete: "tel", inputmode: "tel", }`): Meta attributes of the phone number input.
- `assistive-text` (`string`): Helper text displayed below the input to provide additional context or validation feedback.
- `hint` (`string`): Alternative text that replaces the label when provided. Useful for contextual hints.

### Events

- `@update:model-value` (payload: `value: string | null | undefined`): Emitted when country or phone number changes
- `@data` (payload: `results: MazInputPhoneNumberData`): Emitted when country or phone number changes
- `@country-code` (payload: `countryCode?: CountryCode | null | undefined`): Emitted when selected country changes
- `@update:country-code` (payload: `countryCode?: CountryCode | null | undefined`): Emitted when country changes

### Slots

- `#no-results`: Replace the "no results" icon in the country selector list
- `#selector-flag`: Country selector flag Bindings: `countryCode: CountryCode` (current selected country code Ex: `"FR"`).
- `#country-list-flag`: Country list flag Bindings: `countryCode: CountryCode` (country code of option Ex: `"FR"`), `option: CountryOption` (country data), `isSelected: boolean` (`true` if option is selected).
