Try the examples and choose your framework in any code snippet
Adjust props in real-time and see the results instantly
<script setup lang="ts">
import { ref } from 'vue';
import { PhoneInput } from '@desource/phone-mask-vue';
import '@desource/phone-mask-vue/assets/lib.css';
const phone = ref("");
</script>
<template>
<PhoneInput
v-model="phone"
size="normal"
theme="auto"
:disabled="false"
:readonly="false"
:show-copy="true"
:show-clear="false"
:detect="true"
:with-validity="true"
/>
</template>Simple phone input with country selector
<script setup lang="ts">
import { ref } from 'vue';
import { PhoneInput } from '@desource/phone-mask-vue';
import '@desource/phone-mask-vue/assets/lib.css';
const phone = ref('');
</script>
<template>
<PhoneInput v-model="phone" />
<p>Phone: {{ phone || 'โ' }}</p>
</template>Real-time validation state tracking
<script setup lang="ts">
import { ref } from 'vue';
import { PhoneInput } from '@desource/phone-mask-vue';
import '@desource/phone-mask-vue/assets/lib.css';
const phone = ref('');
const isValid = ref(false);
</script>
<template>
<PhoneInput v-model="phone" @validation-change="isValid = $event" />
<p>{{ isValid ? 'Valid phone number' : phone ? 'Incomplete number' : 'Enter a phone number' }}</p>
</template>Automatically detect country from IP or browser locale
<script setup lang="ts">
import { ref } from 'vue';
import { PhoneInput } from '@desource/phone-mask-vue';
import '@desource/phone-mask-vue/assets/lib.css';
const phone = ref('');
const countryName = ref('');
</script>
<template>
<PhoneInput v-model="phone" detect @country-change="countryName = $event.name" />
<p>Detected Country: {{ countryName || 'Auto-detecting...' }}</p>
</template>Three size options: compact, normal, and large
<script setup lang="ts">
import { ref } from 'vue';
import { PhoneInput } from '@desource/phone-mask-vue';
import '@desource/phone-mask-vue/assets/lib.css';
const phone = ref('');
</script>
<template>
<PhoneInput v-model="phone" size="compact" />
<PhoneInput v-model="phone" size="normal" />
<PhoneInput v-model="phone" size="large" />
</template>Auto, light, and dark themes
<script setup lang="ts">
import { ref } from 'vue';
import { PhoneInput } from '@desource/phone-mask-vue';
import '@desource/phone-mask-vue/assets/lib.css';
const phone = ref('');
const themes = ['auto', 'light', 'dark'] as const;
const selectedTheme = ref<(typeof themes)[number]>('light');
</script>
<template>
<label v-for="theme in themes" :key="theme">
<input v-model="selectedTheme" type="radio" name="theme" :value="theme" />
{{ theme }}
</label>
<PhoneInput v-model="phone" :theme="selectedTheme" />
</template>Built-in copy and clear button functionality
<script setup lang="ts">
import { ref } from 'vue';
import { PhoneInput } from '@desource/phone-mask-vue';
import '@desource/phone-mask-vue/assets/lib.css';
const phone = ref('');
const notification = ref('');
</script>
<template>
<PhoneInput
v-model="phone"
show-copy
show-clear
@copy="notification = 'Copied: ' + $event"
@clear="notification = 'Input cleared'"
/>
<p role="status">{{ notification }}</p>
</template>Control input interaction modes
<script setup lang="ts">
import { ref } from 'vue';
import { PhoneInput } from '@desource/phone-mask-vue';
import '@desource/phone-mask-vue/assets/lib.css';
const disabledPhone = ref('1234567890');
const readonlyPhone = ref('9876543210');
</script>
<template>
<PhoneInput v-model="disabledPhone" disabled />
<PhoneInput v-model="readonlyPhone" readonly />
</template>Use in forms with validation
{
"name": "",
"email": "",
"phone": ""
}<script setup lang="ts">
import { ref } from 'vue';
import { PhoneInput } from '@desource/phone-mask-vue';
import '@desource/phone-mask-vue/assets/lib.css';
const form = ref({ name: '', email: '', phone: '' });
const isValid = ref(false);
const attempted = ref(false);
function submit() {
attempted.value = true;
if (isValid.value) console.log(form.value);
}
</script>
<template>
<form @submit.prevent="submit">
<input v-model="form.name" name="name" autocomplete="name" aria-label="Full Name" placeholder="Full Name" />
<input v-model="form.email" name="email" type="email" autocomplete="email" aria-label="Email Address" placeholder="Email Address" />
<PhoneInput v-model="form.phone" name="phone" @validation-change="isValid = $event" />
<p v-if="attempted && !isValid">Please enter a complete phone number</p>
<button type="submit">Submit</button>
</form>
</template>Use directives in Vue and Angular, a hook in React, or actions and attachments in Svelte. Attachments require Svelte 5.29 or later.
Apply phone masking to any input element
<script setup lang="ts">
import { ref } from 'vue';
import { vPhoneMask, type PMaskPhoneNumber } from '@desource/phone-mask-vue';
const digits = ref('');
const onChange = (phone: PMaskPhoneNumber) => { digits.value = phone.digits; };
</script>
<template>
<label for="phone">Phone number</label>
<input id="phone" type="tel" autocomplete="tel"
v-phone-mask="{ country: 'US', onChange }" />
<p>Digits: {{ digits }}</p>
</template>Configure country and handle change events
<script setup lang="ts">
import { ref } from 'vue';
import { vPhoneMask, type PMaskPhoneNumber } from '@desource/phone-mask-vue';
const country = ref('GB');
const phoneData = ref<PMaskPhoneNumber>({ digits: '', full: '', fullFormatted: '' });
const onChange = (phone: PMaskPhoneNumber) => { phoneData.value = phone; };
</script>
<template>
<label for="country">Country</label>
<select id="country" v-model="country">
<option value="US">United States</option>
<option value="GB">United Kingdom</option>
<option value="DE">Germany</option>
</select>
<label for="phone">Phone number</label>
<input id="phone" type="tel" autocomplete="tel"
v-phone-mask="{ country, onChange }" />
<p>Full: {{ phoneData.full }}</p>
<p>Formatted: {{ phoneData.fullFormatted }}</p>
<p>Digits: {{ phoneData.digits }}</p>
</template>Automatically detect country from IP/locale
<script setup lang="ts">
import { ref } from 'vue';
import { vPhoneMask, type PMaskFull } from '@desource/phone-mask-vue';
const countryName = ref('');
const onCountryChange = (country: PMaskFull) => { countryName.value = country.name; };
</script>
<template>
<label for="phone">Phone number</label>
<input id="phone" type="tel" autocomplete="tel"
v-phone-mask="{ detect: true, onCountryChange }" />
<p>Country: {{ countryName || 'Detectingโฆ' }}</p>
</template>Format phone numbers for text, tables, and contact cards. Choose whether to show the country code and flag.
Choose a country for numbers without a country code. Complete numbers starting with + can be detected automatically; unrecognized values stay unchanged.
<script setup lang="ts">
import { formatPhone } from '@desource/phone-mask-vue/core';
const phone = "+12345678888";
const country = undefined;
const options = { code: true, flag: false };
</script>
<template>
<span>{{ formatPhone(phone, country, options) }}</span>
</template>View source code and contribute
Learn more about the Vue package
Learn more about the Nuxt package
Learn more about the React package
Learn more about the Svelte package
Learn more about the Angular package
Learn more about the TS/JS package
Help improve the library