Menu
Documentation

Phone Input

Optional dependencies

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.

Example

Phone number
Show code
vue
<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>

Country Input

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.

Phone number
Show code
vue
<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>

International and National Formats

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.

Phone number
Show code
vue
<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>

Validation

The component provides a @validation event to indicate if the input value is valid or not

Phone number
Show code
vue
<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>

Disabled State

Phone number
Show code
vue
<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>

Input Size

Show code
vue
<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>

Input Shapes

Show code
vue
<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>

Components

AddonInputPhone