Vue composable
usePhoneInput is a Vue composable you can use to create a custom phone input component. It is used internally by the VPhoneInput Vuetify component. It provides the same behavioral features (automatic formatting, country detection, etc.), but does not provide UI related features (autocomplete, flags, etc.). Every feature which can be used with the composable will have a Composable tag inside this documentation.
Installation
$ npm add v-phone-input$ pnpm add v-phone-input$ yarn add v-phone-input$ bun add v-phone-inputUsage
When using the composable, the first thing to do is to define your reusable phone input component. Inside it, you can use usePhoneInput.
In the following example, we define a PhoneInput component which supports a custom label property and country/phone models. It will render the input through the native HTML select and input elements.
After that, the PhoneInput component is used inside a SignInForm component.
<script
setup
lang="ts"
>
import { usePhoneInput } from 'v-phone-input';
import { toRef, useId } from 'vue';
const props = defineProps<{
label?: string;
}>();
const country = defineModel<string>("country");
const modelValue = defineModel<string>();
const id = useId();
const {
countryInputRef,
phoneInputRef,
countries,
phoneValid,
phone,
countryLabel,
label,
example,
invalidMessage,
} = usePhoneInput({
label: toRef(props, "label"),
country,
modelValue,
});
</script>
<template>
<div :class="$style.phoneInput">
<label
:for="`country-${id}`"
:class="$style.label"
>
{{ countryLabel }}
</label>
<select
ref="countryInputRef"
v-model="country"
:id="`country-${id}`"
:class="$style.input"
>
<option
v-for="country in countries"
:key="`countries-${country.iso2}`"
:value="country.iso2"
>
{{ country.name }}(+{{ country.dialCode }})
</option>
</select>
<label
:for="`phone-${id}`"
:class="$style.label"
>
{{ label }}
</label>
<input
ref="phoneInputRef"
v-model="phone"
:id="`phone-${id}`"
:aria-describedby="`phone-${id}-message`"
type="tel"
:placeholder="example"
:class="$style.input"
>
<p
:id="`phone-${id}-message`"
:class="$style.message"
>
{{ phoneValid ? '' : invalidMessage }}
</p>
</div>
</template>
<style module>
.phoneInput {
display: flex;
flex-direction: column;
}
.label {
font-size: 0.875rem;
margin-block-end: 4px;
}
.input {
font-size: 1rem;
padding: 6px 12px;
margin-block-end: 16px;
border-radius: 8px;
border: 1px solid #eceff1;
background: #eceff1;
}
.message {
font-size: 0.875rem;
margin-block: 0;
}
</style><script
lang="ts"
setup
>
import { ref } from 'vue';
import Definition from './Definition.vue';
const phone = ref('');
const password = ref('');
const onSubmit = async () => {
// ...
};
</script>
<template>
<form @submit.prevent="onSubmit">
<div>
<definition
v-model="phone"
label="Phone"
/>
</div>
<div>
<label for="password">
Password
</label>
<input
id="password"
v-model="password"
name="password"
type="password"
/>
</div>
</form>
</template>INFO
Passing countryInputRef and phoneInputRef is currently only used for on-blur phone formatting.
Configuration
Composable options
To configure usePhoneInput, you can pass an options object. You can explore available options inside compatible features guides. You can also browse VPhoneInputComposableOptions for an exhaustive list where every option is described with its goal, remarks and default value if available.
Most options are using MaybeRef, which means those can be passed as ref or direct values. Passing a ref will make the related behaviors reactive: as an example, passing a reactive displayFormat will make the input value format on every change.
INFO
Only the required modelValue, and optional country, countryInputRef, and phoneInputRef must be refs and cannot be direct values.
<script
lang="ts"
setup
>
import { usePhoneInput } from 'v-phone-input';
import { toRef } from 'vue';
const props = defineProps<{
label?: string;
}>();
const country = defineModel<string>();
const modelValue = defineModel<string>();
const {
// ...
} = usePhoneInput({
// Mandatory reactive options.
country,
modelValue,
// Maybe reactive options.
label: toRef(props, 'label'),
displayFormat: 'e164',
});
</script>Providing default options
If you want to define default values for options, you can also use providePhoneInputOptions to a parent of the component using usePhoneInput.
<script
lang="ts"
setup
>
import { providePhoneInputOptions } from "v-phone-input";
providePhoneInputOptions({
displayFormat: "e164",
});
</script>
<template>
<slot />
</template><script
lang="ts"
setup
>
import PhoneInputOptionsProvider from './PhoneInputOptionsProvider.vue';
import SignInForm from "./SignInForm.vue";
</script>
<template>
<phone-input-options-provider>
Render something deeper which uses phone input...
<sign-in-form />
</phone-input-options-provider>
</template>API reference
You can check out every option and provided value from the composable by reading usePhoneInput.