npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

v-phone-input

v4.4.0

Published

International phone field for Vuetify 3 and Vue 3.

Downloads

13,474

Readme

VPhoneInput

Tests Publish codecov NPM version NPM downloads MIT license

International phone field for Vuetify 3 and Vue 3.

Coming from 2.x.x and upgrading to Vuetify 3? Checkout the migration guide.

Wish to use this package with Vuetify 2? Old version 2.x.x is compatible with Vuetify 2 and Vue 2.

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.

Demo

You can try the VPhoneInput with many options and plugin registration code generation on the GitHub pages demo.

TL;DR

Installation though Yarn:

yarn add v-phone-input flag-icons

Installation though NPM:

npm install v-phone-input flag-icons

Plugin installation:

import 'flag-icons/css/flag-icons.min.css';
import 'v-phone-input/dist/v-phone-input.css';
import { createVPhoneInput } from 'v-phone-input';

const vPhoneInput = createVPhoneInput({
  countryIconMode: 'svg',
});

app.use(vPhoneInput);

If you are using Nuxt, check out the Nuxt setup guide.

Component usage:


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

  const phone = ref('');
</script>

<template>
  <v-phone-input v-model="phone" />
</template>

Documentation

Table of contents

Requirements

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

VPhoneInput utilizes recent ES features that may require polyfills for older browser like Internet Explorer.

Available country guessers requires fetch.

Installation

You can install this package though Yarn:

yarn add v-phone-input flag-icons

Or NPM:

npm install v-phone-input flag-icons

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

Usage

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 'flag-icons/css/flag-icons.min.css';
import 'v-phone-input/dist/v-phone-input.css';
import { createVPhoneInput } from 'v-phone-input';
import { createApp } from 'vue';

const app = createApp(App);

const vPhoneInput = createVPhoneInput({
  countryIconMode: 'svg',
});

app.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.


<script setup>
  import 'flag-icons/css/flag-icons.min.css';
  import 'v-phone-input/dist/v-phone-input.css';
  import { VPhoneInput } from 'v-phone-input';
  import { ref } from 'vue';

  const phone = ref('');
</script>

<template>
  <v-phone-input
      v-model="phone"
      country-icon-mode="svg"
  />
</template>

Migration

Please follow the migration guide if you need to migrate from version 1, 2 or 3.

Nuxt setup

If you are using Nuxt, you must mark v-phone-input as a transpiled package in your Nuxt configuration:

export default defineNuxtConfig({
  build: {
    transpile: [
      // Keep other transpile configuration, such as:
      'vuetify',
      // Add transpile for the package:
      'v-phone-input',
    ],
  },
});

Instead of defining a Vue plugin, you must define a Nuxt plugin as follows:

import 'flag-icons/css/flag-icons.min.css';
import 'v-phone-input/dist/v-phone-input.css';
import { createVPhoneInput } from 'v-phone-input';

export default defineNuxtPlugin((nuxtApp) => {
  const vPhoneInput = createVPhoneInput({
    countryIconMode: 'svg',
  });

  nuxtApp.vueApp.use(vPhoneInput);
});

Props

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 'v-phone-input/dist/v-phone-input.css';
import { createVPhoneInput } from 'v-phone-input';
import { createApp } from 'vue';

const app = createApp(App);

const vPhoneInput = createVPhoneInput({
  label: 'Your phone number',
});

app.use(vPhoneInput);

| Name | Type | Default | Description | |--------------------------|--------------------------------------------------------------------|-----------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------| | label | MessageResolver | Phone | The phone input label (see Localization). | | ariaLabel | MessageResolver | undefined | The phone input aria-label (see Localization). | | countryLabel | MessageResolver | Country | The country input label (see Localization). | | countryAriaLabel | MessageResolver | Country for {label} | The phone input aria-label (see Localization). | | placeholder | MessageResolver | undefined | The phone input placeholder (see Localization). | | hint | MessageResolver | undefined | The phone input hint (see Localization). | | invalidMessage | MessageResolver or null | The "{label}" field is not a valid phone number (example: {example}). | The phone input message when number is invalid (see Localization). You can pass null to disable default validation. | | example | string or Function or undefined | undefined | Example of a valid phone number (or factory function which takes a Country[] object) to customize phone number example for message. | | countryIconMode | string or VueConstructor or undefined | undefined | The country icon display mode (see Country icon modes). | | allCountries | Country[] | An array of all possible countries | Array of countries to use. | | preferCountries | CountryOrIso2[] | [] | Array of countries' codes to propose as first option of country input. | | includeCountries | CountryOrIso2[] | [] | Array of countries' codes to include as options of country input. | | excludeCountries | CountryOrIso2[] | [] | Array of countries' codes to exclude from options of country input. | | defaultCountry | CountryOrIso2 | undefined | Default country to select when not guessing nor detecting from current value. | | countryGuesser | CountryGuesser or PreferableCountryGuesser | new MemoIp2cCountryGuesser() | Country guesser implementation to use when guessing country (see Country guesser). | | guessCountry | boolean | false | Enable guessing country using default or provided country guesser. | | disableGuessLoading | boolean | false | Disable passing the country input in a loading state when guessing country. | | enableSearchingCountry | boolean | false | Turns the country input into a VAutocomplete input (see Enabling searching countries example). | | rules | Function[] or string[] | [] | Additional rules to pass to phone input (see Validation example). | | displayFormat | PhoneNumberFormat | 'national' | Format to use when displaying valid phone numbers in phone text input (see Phone number formats). | | country | string | '' | Country of the country input. Can be used with .sync modifier. Will be superseded by value's country if defined on mounting. | | value | string | '' | Value of the phone input. You may use it using v-model or @input. | | wrapperProps | object | {} | Props to pass to the inputs wrapper div element. | | countryProps | object | {} | Props to pass to the VSelect or VAutocomplete country input component. | | phoneProps | object | {} | Props to pass to the VTextField phone input component. |

Props inheritance

You can also pass the Vuetify VTextField and Vuetify VSelect props to the component to customize variant, icons, errors, etc. using the v-bind directive or the countryProps and phoneProps props.

Most props will only apply to the phone input component (not wrapper div or country select), but be aware that:

  • Some props will only apply to the inputs wrapper div element: id, class and style.
  • Some props are applied to both inputs: variant, flat, tile, density, singleLine, hideDetails, direction, reverse, color, bgColor, theme, disabled, readonly, and rounded.

Events

| Name | Type | Description | |---------------------|---------------------------|------------------------------------------------------------------------------------| | update:modelValue | string | Emitted when the country or phone is updated with the E164 formatted phone number. | | update:country | CountryIso2 | Emitted when the country is updated with the selected country. |

You can also bind to the Vuetify VTextField and Vuetify VSelect events using the v-bind directive or the countryProps and phoneProps props.

Slots

Each slots with a country: prefix are passed to the country input, other slots are passed to the phone input.


<template>
  <v-phone-input>
    <template #country:label>
      Label for country
    </template>
    <template #label>
      Label for phone
    </template>
  </v-phone-input>
</template>

The input also provides 4 special slots:

  • country-selection for countries' display in selection.
  • country-icon for countries' icons display in selection and select items.
  • country-name for countries' name display in select items.
  • country-append for countries' appended info display in select items.

Each of those slots will receive a country object property. country-icon slot will also receive a decorative boolean property, which will be false inside selection, and true inside select item.


<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 }">
      {{ country.name }}
    </template>
    <template #country-append="{ country }">
      <strong>+{{ country.dialCode }}</strong>
    </template>
  </v-phone-input>
</template>

Examples

Country icon modes

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

SVG

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 'flag-icons/css/flag-icons.min.css';

const vPhoneInput = createVPhoneInput({
  countryIconMode: 'svg',
});
Sprite

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

import 'world-flags-sprite/stylesheets/flags32.css';

const vPhoneInput = createVPhoneInput({
  countryIconMode: 'sprite',
});
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 { defineComponent, h } from 'vue';

const vPhoneInput = createVPhoneInput({
  countryIconMode: defineComponent({
    setup(props) {
      return () => h('span', {}, [props.country.name]);
    },
  }),
});
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 slot of country input.

Validation

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:


<script setup>
  const rules = [
    (value, phone, { label, country, example }) => !!value || `The "${label}" field is required.`,
  ];
</script>

<template>
  <v-phone-input :rules="rules" />
</template>

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:

Disabling default validation

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

<template>
  <v-phone-input :invalid-message="null" />
</template>

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 vite-plugin-vuetify).

When using plugin registration

To enable searching countries for all inputs as a default behavior, you must register the VAutocomplete component globally inside your plugin definition.

import 'flag-icons/css/flag-icons.min.css';
import 'v-phone-input/dist/v-phone-input.css';
import { createVPhoneInput } from 'v-phone-input';
import { VAutocomplete } from 'vuetify/components';

// ...your Vue app creation.

// IMPORTANT: required when treeshaking Vuetify components.
app.component('VAutocomplete', VAutocomplete);

const vPhoneInput = createVPhoneInput({
  enableSearchingCountry: true,
});

app.use(vPhoneInput);

After this setup, all v-phone-input will be using an autocomplete input for country by default.

When using per-file registration

To enable searching countries on a per-file basis, you must register the VAutocomplete component inside your app definition.

import { VAutocomplete } from 'vuetify/components';

// ...your Vue app creation.

// IMPORTANT: required when treeshaking Vuetify components.
app.component('VAutocomplete', VAutocomplete);

After this setup, you can safely enable the enable-searching-country property.


<script setup>
  import 'flag-icons/css/flag-icons.min.css';
  import 'v-phone-input/dist/v-phone-input.css';
  import { VPhoneInput } from 'v-phone-input';
</script>

<template>
  <v-phone-input enable-searching-country />
</template>

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:

const vPhoneInput = createVPhoneInput({
  displayFormat: 'international',
});

Localization

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:

// 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.global.t('phone.phoneLabel'),
  countryLabel: i18n.global.t('phone.phoneCountry'),
  countryAriaLabel: (options) => i18n.global.t('phone.phoneCountryFor', options),
  invalidMessage: (options) => i18n.global.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 sure to provide an explicit countryAriaLabel when doing so).

Dependencies

VPhoneInput relies on multiple dependencies to work:

Types

Country

A country ISO-2 code is a string containing 2 uppercase characters representing a country (e.g. FR for France).

A country object contains information about a country.

type CountryIso2 = string;

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

export type CountryOrIso2 = Country | CountryIso2;

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 guessed country on future calls.

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

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;
  country: Country;
  example: string;
}

Message

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

export type Message = string | undefined;

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;

Contributing

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.

Credits

Inspired by vue-tel-input and vue-tel-input-vuetify.

License

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