業務で国際SMS認証の入力画面をVueで作ることになり、何か良いライブラリがないか探していたところ、国際電話番号の入力補助とバリデーションを行うライブラリである International Telephone Input (intl-tel-input)がちょうどVue Componentに対応したとのニュースがあったため、intl-tel-inputを試してみました。
自動的に国コードもつなげた形に変換してくれ、携帯電話番号のフォーマットになっているかバリデーションも行なってくれる優れたライブラリだったので簡単な使い方をご紹介できればと思います。

導入方法

私が検証した環境は下記となります
・node: v22.12.0
・vue: 3.5.18
・vite: 7.1.1
・intl-tel-input: 25.3.2

Vueのプロジェクトディレクトリで下記を実行します
npm install intl-tel-input@latest

その後SMS用の電話番号入力コンポーネントを置きたいVueファイルに下記を定義することでIntlTelInputコンポーネントを使用することができるようになります。

import IntlTelInput from 'intl-tel-input/vueWithUtils'
import 'intl-tel-input/styles'


私が作成したサンプルのコンポーネントは下記となります

<template>
  <div class="phone-input-container">
    <h2>International Phone Number Input Sample</h2>
    <div class="form-group">
      <label for="phone">電話番号:</label>
      <IntlTelInput
        ref="telRef"
        :inputProps="{ id: 'phone', class: 'phone-input', placeholder: '電話番号' }"
        :options="{
          initialCountry: 'jp',
          separateDialCode: false,
          excludeCountries: [
              'by',
              'eg',
              'jo',
              'kw',
              'qa',
              'lk',
              'tr',
              'ae',
              'vn'
          ]
        }"
        @changeNumber="onChangeNumber"
        @changeValidity="onChangeValidity"
        @changeCountry="onChangeCountry"
      />
    </div>
    
    <div class="phone-info" v-if="phoneNumber">
      <h3>電話番号情報:</h3>
      <p><strong>入力値:</strong> {{ phoneNumber }}</p>
      <p><strong>フォーマット済み:</strong> {{ formattedNumber }}</p>
      <p><strong>国コード:</strong> {{ selectedCountryData?.iso2 || 'N/A' }}</p>
      <p><strong>有効性:</strong> 
        <span :class="{ 'valid': isValid, 'invalid': !isValid }">
          {{ isValid ? '有効' : '無効' }}
        </span>
      </p>
    </div>
  </div>
</template>

<script>
import { ref } from 'vue'
import IntlTelInput from 'intl-tel-input/vueWithUtils'
import 'intl-tel-input/styles'

export default {
  name: 'PhoneNumberInput',
  components: { IntlTelInput },
  setup() {
    const telRef = ref(null)
    const phoneNumber = ref('')
    const formattedNumber = ref('')
    const selectedCountryData = ref(null)
    const isValid = ref(false)

    const updateFromInstance = () => {
      const instance = telRef.value?.instance
      if (!instance) return
      try {

        formattedNumber.value = instance.getNumber() || ''
        selectedCountryData.value = instance.getSelectedCountryData?.() || null
      } catch (e) {
        formattedNumber.value = ''
      }
    }

    const onChangeNumber = (num) => {
      phoneNumber.value = num || ''
      updateFromInstance()
    }

    const onChangeValidity = (valid) => {
      isValid.value = !!valid
    }

    const onChangeCountry = (iso2) => {
      // iso2は受け取れるが、詳細データはインスタンスから取得
      updateFromInstance()
    }

    return {
      telRef,
      phoneNumber,
      formattedNumber,
      selectedCountryData,
      isValid,
      onChangeNumber,
      onChangeValidity,
      onChangeCountry
    }
  }
}
</script>

<style scoped>
.phone-input-container {
  max-width: 600px;
  min-height: 90vh;
  margin: 0 auto;
  padding: 20px;
  font-family: Arial, sans-serif;
}

.form-group {
  margin-bottom: 20px;
}

label {
  display: block;
  margin-bottom: 8px;
  font-weight: bold;
  color: #333;
}

.phone-input {
  width: 100%;
  padding: 10px;
  border: 2px solid #ddd;
  border-radius: 4px;
  font-size: 16px;
  transition: border-color 0.3s ease;
}

.phone-input:focus {
  outline: none;
  border-color: #007bff;
}

.phone-info {
  background-color: #f8f9fa;
  padding: 20px;
  border-radius: 8px;
  border: 1px solid #e9ecef;
}

.phone-info h3 {
  margin-top: 0;
  color: #495057;
}

.phone-info p {
  margin: 8px 0;
}

.valid {
  color: #28a745;
  font-weight: bold;
}

.invalid {
  color: #dc3545;
  font-weight: bold;
}

/* intl-tel-inputのスタイルのカスタマイズ */
:global(.iti) {
  width: 100%;
}

:global(.iti__country-list) {
  max-height: 200px;
  overflow-y: auto;
}
</style>

サンプルの画面キャプチャ

ビルドするとこのようなコンポーネントになります。
国旗をクリックするとプルダウンが表示されSearchの入力領域で文字での絞り込みも可能です

サンプルについての解説

inputPropsについて

入力領域のid、class、プレースホルダの設定を行なっています。

optionsについて

initialCountry

デフォルトとする国コードの設定を行えます。今回は日本(jp)を設定しています。

separateDialCode

trueを設定すると国コードが表示されます。falseにすると国コードは表示されませんが、
内部の番号は国コードがついた形で管理されます。
(例:国コードが日本設定で090-1111-1111の時、+819011111111となる)

excludeCountries

SMS配信サービスによっては対象外となる国があるかと思います。
その際はこのオプションで配列を指定することであらかじめ国コードの選択肢から外すことができます。
設定する国のコードはISO 3166-1 alpha-2 準拠となっていますのでコードを設定すると選択肢の中から対応する国が除外されます。

@changeNumber

電話番号の入力領域に変更があった時に発火するコールバック関数です
サンプルでは入力された結果で入力値やフォーマット済みの内容を更新しています

@changeValidity

電話番号の入力内容のバリデーションが成功<->失敗で切り替わった時に発火するコールバック関数です。
サンプルでは有効性を更新しています

@changeCountry

国コードを切り替えた時に発火するコールバック関数です。
サンプルでは国コードの内容を更新しています。

以上、みなさまのSMS認証画面開発の手助けとなれば幸いです。



ギャップロを運営しているアップフロンティア株式会社では、一緒に働いてくれる仲間を随時、募集しています。 興味がある!一緒に働いてみたい!という方は下記よりご応募お待ちしております。
採用情報をみる