This component uses the libphonenumber-js and the country-codes-list packages to detect and validate the phone input value.
Ready to use phone input component with country code dropdown, with validation and formatting.
<script lang="ts" setup>
const phone = ref('')
</script>
<template>
<div class="max-w-md">
<BaseField label="Phone number">
<LazyAddonInputPhone
v-model="phone"
placeholder="Ex: +1 555 555 5555"
/>
</BaseField>
</div>
</template>
The component provides a country dropdown to select the country code, you can use the country
prop to set the default country, otherwise it will be detected from the user's input.
You can use the v-model:country
notation to get the selected/detected country code.
<script lang="ts" setup>
const phone = ref('+1 555 555 5555')
const country = ref('US')
</script>
<template>
<div class="max-w-md">
<BaseField label="Phone number">
<LazyAddonInputPhone
v-model="phone"
v-model:country="country"
/>
</BaseField>
</div>
</template>
By default, the input value will be formatted in the international format, you can change this behavior with the format
prop to change it to national
.
<script lang="ts" setup>
const phone = ref('+1 555 555 5555')
</script>
<template>
<div class="max-w-md">
<BaseField label="Phone number">
<LazyAddonInputPhone
v-model="phone"
format="national"
country="US"
/>
</BaseField>
</div>
</template>
The component provides a @validation
event to indicate if the input value is valid or not
<script lang="ts" setup>
import type { AddonInputPhone } from '#components'
const phone = ref('012345')
const error = ref('')
const inputRef = ref<InstanceType<typeof AddonInputPhone>>()
function onSubmit() {
if (!inputRef.value?.validation?.valid) {
error.value = 'Please enter a valid phone number'
return
}
// eslint-disable-next-line no-alert
alert(`Selected: ${inputRef.value?.currentCountry?.label}`)
}
function onValidate(state: { valid: boolean, touched: boolean, error: string }) {
if (!state.error) {
error.value = ''
return
}
switch (state.error) {
case 'INVALID_COUNTRY':
error.value = 'Please select a country'
break
case 'NO_POSSIBLE_COUNTRIES':
error.value = 'No possible countries for this phone number'
break
case 'PHONE_NUMBER_NOT_POSSIBLE':
error.value = 'This phone number is not valid for the selected country'
break
case 'NOT_A_NUMBER':
case 'TOO_SHORT':
case 'TOO_LONG':
default:
error.value = 'Please enter a valid phone number'
break
}
}
</script>
<template>
<form class="max-w-md" @submit.prevent="onSubmit">
<BaseField
v-slot="{ inputAttrs }"
label="Phone number"
:state="error ? 'error' : 'idle'"
:error="error"
>
<LazyAddonInputPhone
ref="inputRef"
v-model="phone"
placeholder="Type to try validation"
v-bind="inputAttrs"
@validation="onValidate"
/>
</BaseField>
</form>
</template>
<script lang="ts" setup>
const phone = ref('+1 555 555 5555')
</script>
<template>
<div class="max-w-md">
<BaseField label="Phone number">
<LazyAddonInputPhone
v-model="phone"
disabled
/>
</BaseField>
</div>
</template>
<script lang="ts" setup>
const phone = ref('+33612345678')
const country = ref('FR')
</script>
<template>
<div class="flex flex-wrap gap-4 sm:flex-nowrap">
<LazyAddonInputPhone
v-model="phone"
v-model:country="country"
size="sm"
/>
<LazyAddonInputPhone
v-model="phone"
v-model:country="country"
size="md"
/>
<LazyAddonInputPhone
v-model="phone"
v-model:country="country"
size="lg"
/>
</div>
</template>
<script lang="ts" setup>
const phone = ref('+33612345678')
const country = ref('FR')
</script>
<template>
<div class="grid gap-4 sm:grid-cols-2">
<LazyAddonInputPhone
v-model="phone"
v-model:country="country"
rounded="none"
/>
<LazyAddonInputPhone
v-model="phone"
v-model:country="country"
rounded="sm"
/>
<LazyAddonInputPhone
v-model="phone"
v-model:country="country"
rounded="md"
/>
<LazyAddonInputPhone
v-model="phone"
v-model:country="country"
rounded="lg"
/>
<LazyAddonInputPhone
v-model="phone"
v-model:country="country"
rounded="full"
/>
</div>
</template>