Exciting release!Introducing "safe npm". Learn more
Log inDemoInstall


Package Overview
File Explorer

Advanced tools


International phone field for Vuetify 2.0 and Vue JS 2.


Version published
Weekly downloads
increased by48.28%

Weekly downloads




Migration to Vite bundler, plugin registration changes and dependencies upgrade.


Check the migration guide inside the documentation.

  • Plugin is now created using a factory exported as a named member createVPhoneInput. Options need to be passed to this factory instead of the Vue.use registration.
  • CSS styles have been extracted into a dedicated dist/v-phone-input.css.




Tests Publish codecov NPM version NPM downloads MIT license

International phone field for Vuetify 2.0 and Vue JS 2.

Version 2 with better support for ES Modules, provided by Vite, is now released. Check out the migration guide.

Proudly supported by the CoWork'HIT.

Motivation: There are already multiple libraries to provide phone number input on Vuetify. But for those already published are not actively maintained or does not put focus on providing great accessibility. This new library aims to provide those two.


You can try the VPhoneInput with major options configuration on the GitHub pages demo.

On the demo, you'll be able to try out the field option and generate your plugin registration options.


Installation though Yarn:

yarn add v-phone-input flag-icons

Installation though NPM:

npm install v-phone-input flag-icons

Plugin installation:

import Vue from 'vue'; import { createVPhoneInput } from 'v-phone-input'; import 'v-phone-input/dist/v-phone-input.css'; import 'flag-icons/css/flag-icons.min.css'; const vPhoneInput = createVPhoneInput({ countryIconMode: 'svg', }); Vue.use(vPhoneInput);

Component usage:

<template> <v-phone-input v-model="phone" /> </template> <script> export default { data: () => ({ phone: '' }), }; </script>


Table of contents


VPhoneInput requires Vue@2 and Vuetify@2 to be installed and working in your project.

VPhoneInput utilizes features of ES2015/2017 that require the need to use polyfills for Internet Explorer 11 and Safari 9/10.

Available country guessers requires fetch.


You can install this package though Yarn:

yarn add v-phone-input flag-icons


npm install v-phone-input flag-icons

flag-icons package is required if you want the input to display countries' flags.


You can globally define the input using the provided plugin factory. This will register the v-phone-input component globally. You must also import the package additional CSS.

import Vue from 'vue'; import { createVPhoneInput } from 'v-phone-input'; import 'v-phone-input/dist/v-phone-input.css'; import 'flag-icons/css/flag-icons.min.css'; const vPhoneInput = createVPhoneInput({ countryIconMode: 'svg', }); Vue.use(vPhoneInput);

You may also only define the field on a per-file basis. Notice that with this method, you won't be able to define props' default values for the input.

<template> <v-phone-input v-model="phone" country-icon-mode="svg" /> </template> <script> import { VPhoneInput } from 'v-phone-input'; import 'v-phone-input/dist/v-phone-input.css'; import 'flag-icons/css/flag-icons.min.css'; export default { components: { VPhoneInput }, data: () => ({ // Phone value will be a E164 formatted phone number (example: +33123456789). phone: '', }), }; </script>


Migrate from 1.x.x to 2.x.x

Upgrade the package version with Yarn:

yarn upgrade v-phone-input@^2.0.0

If you are using the plugin the global plugin registration method, you need to update the file where you are defining it:

import Vue from 'vue'; - import VPhoneInputPlugin from 'v-phone-input'; + import { createVPhoneInput } from 'v-phone-input'; + import 'v-phone-input/dist/v-phone-input.css'; import 'flag-icons/css/flag-icons.min.css'; - Vue.use(VPhoneInputPlugin, { countryIconMode: 'svg' }); + const vPhoneInput = createVPhoneInput({ countryIconMode: 'svg' }); + Vue.use(vPhoneInput);

CSS have been extracted to a file, so you'll also need to import v-phone-input/dist/v-phone-input.css (even if you are using the per-file registration), like in the example above.


VPhoneInput provides many props to customize the input behaviors or display.

You may pass those props directly the input:

<template> <v-phone-input label="Your Phone number" /> </template>

Or define them as default values when creating the plugin:

import Vue from 'vue'; import { createVPhoneInput } from 'v-phone-input'; import 'v-phone-input/dist/v-phone-input.css'; const vPhoneInput = createVPhoneInput({ label: 'Your phone number', }); Vue.use(vPhoneInput);
labelMessageResolverPhoneThe phone input label (see Localization).
ariaLabelMessageResolverundefinedThe phone input aria-label (see Localization).
countryLabelMessageResolverCountryThe country input label (see Localization).
countryAriaLabelMessageResolverCountry for {label}The phone input aria-label (see Localization).
placeholderMessageResolverundefinedThe phone input placeholder (see Localization).
hintMessageResolverundefinedThe phone input hint (see Localization).
invalidMessageMessageResolverThe "{label}" field is not a valid phone number (example: {example}).The phone input message when number is invalid (see Localization).
countryIconModestring or VueConstructor or undefinedundefinedThe country icon display mode (see Country icon modes).
allCountriesCountry[]An array of all possible countriesArray of countries to use.
preferredCountriesCountryIso2[][]Array of countries' codes to propose as first option of country input.
onlyCountriesCountryIso2[][]Array of countries' codes to display as options of country input (will hide others).
ignoredCountriesCountryIso2[][]Array of countries' codes to hide from country input.
defaultCountryCountryIso2undefinedDefault country to select when not guessing nor detecting from current value.
countryGuesserCountryGuesser or PreferableCountryGuessernew MemoIp2cCountryGuesser()Country guesser implementation to use when guessing country (see Country guesser).
disableGuessingCountrybooleanfalseDisable guessing country.
disableGuessLoadingbooleanfalseDisable passing the country input in a loading state when guessing country.
enableSearchingCountrybooleanfalseTurns the country input into a VAutocomplete input (see Enabling searching countries example).
rulesFunction[] or string[][]Additional rules to pass to phone input (see Validation example).
displayFormatPhoneNumberFormat'national'Format to use when displaying valid phone numbers in phone text input (see Phone number formats).
countrystring''Country of the country input. Can be used with .sync modifier. Will be superseded by value's country if defined on mounting.
valuestring''Value of the phone input. You may use it using v-model or @input.
countryPropsobject{}Props to pass to the VSelect or VAutocomplete country input component.
phonePropsobject{}Props to pass to the VTextField phone input component.

You can also pass the Vuetify VTextField props to the component to customize display, errors, etc.


inputstringEmitted when the country or phone is updated with the E164 formatted phone number.
update:countryCountryIso2Emitted when the country is updated with the selected country.

All the Vuetify VTextField events are also re-emitted by the input.


The following slots are passed to the country select input ( see v-select API):

  • selection
  • item

The following slots are passed to the phone text input ( see v-text-field API):

  • append
  • append-outer
  • counter
  • label
  • message
  • prepend
  • prepend-inner
  • progress

The input also provides two special slots: the country-icon slot for countries' icons display and country-name slot for countries' name display.

<template> <v-phone-input> <template #country-icon="{ country, decorative }"> <img :src="`path/to/flags/${country.iso2}.png`" :alt="decorative ? '' : country.name" > </template> <template #country-name="{ country }"> <strong>+{{ country.dialCode }}</strong> {{ country.name }} </template> </v-phone-input> </template>


Country icon modes

With VPhoneInput, you can choose between 5 country icon modes which are changing the way the country input will display.


This is the proposed way to use the input. Rely on an SVG flag icons package. You must install flag-icons package to use it.

import Vue from 'vue'; import { createVPhoneInput } from 'v-phone-input'; import 'v-phone-input/dist/v-phone-input.css'; import 'flag-icons/css/flag-icons.min.css'; const vPhoneInput = createVPhoneInput({ countryIconMode: 'svg', }); Vue.use(vPhoneInput);

Rely on a CSS sprite flag icons package. You must install world-flags-sprite package to use it.

import Vue from 'vue'; import { vPhoneInput } from 'v-phone-input'; import 'v-phone-input/dist/v-phone-input.css'; import 'world-flags-sprite/stylesheets/flags32.css'; const vPhoneInput = createVPhoneInput({ countryIconMode: 'sprite', }); Vue.use(vPhoneInput);
Custom component

This allows you to register a custom component to display country icons. Component will receive country and decorative props. We provide a simple VPhoneCountrySpan component to simplify using a CSS class image based icon system (such as another CSS sprite file).

import Vue from 'vue'; import { createVPhoneInput, VPhoneCountrySpan } from 'v-phone-input'; import 'v-phone-input/dist/v-phone-input.css'; import 'your/awesome/flag-sprite.css'; const vPhoneInput = createVPhoneInput({ countryIconMode: { functional: true, render: (h, { props }) => h(VPhoneCountrySpan, { staticClass: `awesome-flag awesome-flag-${props.country.iso2.toLowerCase()}`, props, }), }, }); Vue.use(vPhoneInput);
Custom slot

See the slots section.

No icon

This is the default behavior when not overriding options or props default values. This will not display an icon inside the list, but will show the ISO-2 code inside the selection for screen readers users.


By default , the input will validate that the phone number is a valid one by injecting a rules to the phone text input.

You may add any additional rules by providing a rules prop to the input:

<template> <v-phone-input :rules="rules" /> </template> <script> export default { computed: { rules() { return [ (value, phone, { label, example }) => !!value || `The "${label}" field is required.`, ]; }, }, }; </script>

Any rule you pass as a function will receive 3 arguments (instead of one for default Vuetify rules) that you may use when validating user's input:

  • value: the value contained in the phone text input.
  • phone: the phone number object.
  • messageOptions: the message options which you may use to inject the input label or a phone example inside the message.

If you don't want the automatic validation to run, you can pass a null value to the invalid-message prop.

Enabling searching countries

You may provide a enableSearchingCountry with a true value to enable textual search in countries.

Since VPhoneInput does not import VAutocomplete to reduce its weight, you might need to provide this component to Vue when treeshaking Vuetify components (e.g. when using vuetify-loader).

To enable searching countries for all inputs as a default behavior:

import Vue from 'vue'; import { VAutocomplete } from 'vuetify/lib'; import { createVPhoneInput } from 'v-phone-input'; import 'v-phone-input/dist/v-phone-input.css'; // IMPORTANT: required when treeshaking Vuetify components. Vue.component('VAutocomplete', VAutocomplete); const vPhoneInput = createVPhoneInput({ enableSearchingCountry: true, }); Vue.use(vPhoneInput);

To enable searching countries on a per-input basis:

<template> <v-phone-input enable-searching-country /> </template> <script> import { VAutocomplete } from 'vuetify/lib'; export default { // IMPORTANT: required when treeshaking Vuetify components. components: { VAutocomplete }, }; </script>
Customizing display format

By default, valid phone number will be formatted using the national format. You can customize the display format using the displayFormat prop/option:

import Vue from 'vue'; import { createVPhoneInput } from 'v-phone-input'; import 'v-phone-input/dist/v-phone-input.css'; const vPhoneInput = createVPhoneInput({ displayFormat: 'international', }); Vue.use(vPhoneInput);

Localizable props may be defined on a per-input basis:

<template> <v-phone-input label="Phone number" country-label="Country" country-aria-label="Country for phone number" invalid-message="Phone number must be a valid phone number (example: 01 23 45 67 89)." /> </template>

Localizable props can also be defined for all inputs as a default behavior:

import Vue from 'vue'; import { createVPhoneInput } from 'v-phone-input'; import 'v-phone-input/dist/v-phone-input.css'; // Example without any localization library. const vPhoneInput = createVPhoneInput({ label: 'Phone number', countryLabel: 'Country', countryAriaLabel: ({ label }) => `Country for ${label}`, invalidMessage: ({ label, example }) => `${label} must be a valid phone number (example: ${example}).`, }); // Example with Vue-I18N localization library. import i18n from './path/to/i18n-plugin'; const vPhoneInput = createVPhoneInput({ label: i18n.t('phone.phoneLabel'), countryLabel: i18n.t('phone.phoneCountry'), countryAriaLabel: (options) => i18n.t('phone.phoneCountryFor', options), invalidMessage: (options) => i18n.t('phone.invalidPhoneGiven', options), });

Any localizable prop is a message resolver. Notice that for label and ariaLabel props, no label will be defined for the message resolver's options.

To disable a message, you should pass null (instead of undefined). This way, you'll be able to disable the country label for example (be sur to provide an explicit countryAriaLabel when doing so).


VPhoneInput relies on multiple dependencies to work:


Country ISO-2

A country ISO-2 code is a string containing 2 uppercase characters.

type CountryIso2 = string;

A country object contains information about a country.

interface Country { name: string; // Example: "France". iso2: CountryIso2; // Example: "FR". dialCode: string; // Example: "33". }
Country Guesser

A country guesser is a class implementing CountryGuesser interface and providing a guess method to detect the default country to use.

interface CountryGuesser { guess: () => Promise<CountryIso2 | undefined>; }

This package ships with two CountryGuesser implementations:

  • Ip2cCountryGuesser which uses IP2C service to guess the country from the client's IP. Notice that IP2C service might not work when using an add blocking extension.
  • MemoIp2cCountryGuesser (default) which memoize the result of Ip2cCountryGuesser promise into a class property.
  • StorageMemoIp2cCountryGuesser which memoize the result of Ip2cCountryGuesser promise into a storage implementation (defaults to localStorage).

A preferable country guesser is a country guesser with the capability to use the user preference instead of the memoized guessed country.

interface PreferableCountryGuesser extends CountryGuesser { setPreference: (country: CountryIso2) => void; }

MemoIp2cCountryGuesser and StorageMemoIp2cCountryGuesser are implementations of the PreferableCountryGuesser interface. They store the country (when changed using the input) to return it instead of the guessed country on future guess call.

Phone Number Formats

A phone number format is a string representing a format, allowing to change the display format of a phone number in input. Here are the available format (provided by awesome-phonenumber):

  • e164: +46707123456
  • international: +46 70 712 34 56
  • national: 070-712 34 56
  • rfc3966: tel:+46-70-712-34-56
  • significant: 707123456
Phone Number

A phone number is a simple object describing the VPhoneInput current value. The number key will contain an input string and may contain each formatted value if the phone number is valid.

type PhoneNumberObject = { number: { input: string } & Partial<Record<PhoneNumberFormat, string>>; possibility: string; possible: boolean; valid: boolean; regionCode: CountryIso2 | undefined; }
Message options

An object containing the input label (or aria-label if no label) and an example of a valid phone number for active country.

type MessageOptions = { label?: Message; example: string; }

A type representing a localized message for the input which will be used as the label, hint, etc.

export type Message = string | undefined | null;
Message resolver

A type representing a function to resolve a message using current message options or directly the message.

export type MessageResolver = ((options: MessageOptions) => Message) | Message;


Please see CONTRIBUTING file for more details.

Informal discussion regarding bugs, new features, and implementation of existing features takes place in the GitHub issue page of this repository.


Inspired by vue-tel-input and vue-tel-input-vuetify. Library skeleton generated by vue-sfc-rollup.


v-phone-input is an open-sourced software licensed under the MIT license.



Last updated on 28 Jul 2022

Did you know?

Socket installs a Github app to automatically flag issues on every pull request and report the health of your dependencies. Find out what is inside your node modules and prevent malicious activity before you update the dependencies.

Install Socket
support@socket.devSocket SOC 2 Logo


  • Package Issues
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc