@desource/phone-mask-nuxt
v0.3.0
Published
π― Zero-config Nuxt module for international phone masking. Powered by @desource/phone-mask with Google libphonenumber sync.
Maintainers
Readme
@desource/phone-mask-nuxt
Nuxt module for phone input with Google's libphonenumber data
Drop-in Nuxt module with auto-imports, SSR support, and zero configuration.
β¨ Features
- π― Zero Config β Works out of the box
- π Auto-imports β Components and composables
- π SSR Compatible β Server-side rendering ready
- π¨ Styleable β Bring your own styles or use defaults
- π§ TypeScript β Fully typed
- β‘ Optimized β Tree-shaking and code splitting
π¦ Installation
npm install @desource/phone-mask-nuxt
# or
yarn add @desource/phone-mask-nuxt
# or
pnpm add @desource/phone-mask-nuxtπ Setup
Add the module to your nuxt.config.ts:
export default defineNuxtConfig({
modules: ['@desource/phone-mask-nuxt']
});That's it! The component and directive are now auto-imported.
π Usage
Basic Component
<template>
<div>
<PhoneInput v-model="phone" country="US" />
<p>Phone: {{ phone }}</p>
</div>
</template>
<script setup lang="ts">
const phone = ref('');
</script>With Auto-detection
<template>
<PhoneInput v-model="phone" detect @country-change="onCountryChange" />
</template>
<script setup>
const phone = ref('');
const onCountryChange = (country) => {
console.log('Detected country:', country.name);
};
</script>Using the Directive
<template>
<div class="phone-wrapper">
<select v-model="selectedCountry">
<option value="US">πΊπΈ +1</option>
<option value="GB">π¬π§ +44</option>
<option value="DE">π©πͺ +49</option>
</select>
<input
v-phone-mask="{
country: selectedCountry,
onChange: handleChange
}"
class="phone-input"
/>
</div>
</template>
<script setup>
const selectedCountry = ref('US');
const phone = ref('');
const handleChange = (fullNumber, digits) => {
phone.value = fullNumber;
};
</script>βοΈ Configuration
Module Options
Configure the module in nuxt.config.ts:
export default defineNuxtConfig({
modules: ['@desource/phone-mask-nuxt'],
phoneMask: {
// Import styles automatically
css: true, // Default: true
// Register PhoneInput component
component: true, // Default: true
// Register v-phone-mask directive
directive: true, // Default: true
// Register shared helpers and types
helpers: true // Default: true
}
});Custom Styling
Option 1: Disable auto CSS import
export default defineNuxtConfig({
modules: ['@desource/phone-mask-nuxt'],
phoneMask: {
css: false // Don't auto-import styles
}
});Then import manually where needed:
<style>
@import '@desource/phone-mask-vue/assets/lib.css';
/* Your custom overrides */
.phone-input {
--pi-border: #your-color;
}
</style>Option 2: Override CSS variables
<style>
:root {
--pi-bg: #f9fafb;
--pi-border: #e5e7eb;
--pi-border-focus: #3b82f6;
--pi-text: #111827;
}
</style>π§ TypeScript
The module provides automatic TypeScript support. Types are available globally:
// Auto-imported types
import type {
PCountryKey,
PMaskBase,
PMaskBaseMap,
PMask,
PMaskMap,
PMaskWithFlag,
PMaskWithFlagMap,
PMaskFull,
PMaskFullMap,
PMaskPhoneNumber
} from '#phone-mask';π Examples
Form Integration
<template>
<form @submit.prevent="handleSubmit">
<div>
<label for="name">Name</label>
<input id="name" v-model="form.name" type="text" />
</div>
<div>
<label for="phone">Phone</label>
<PhoneInput id="phone" v-model="form.phone" country="US" @validation-change="phoneValid = $event" />
</div>
<button type="submit" :disabled="!phoneValid">Submit</button>
</form>
</template>
<script setup>
const form = reactive({
name: '',
phone: ''
});
const phoneValid = ref(false);
const handleSubmit = () => {
console.log('Form data:', form);
};
</script>With Pinia Store
// stores/user.ts
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', {
state: () => ({
phoneDigits: '',
country: 'US'
}),
actions: {
setPhoneDigits(phone: string) {
this.phone = phone;
},
setCountry(id: string) {
this.country = id;
}
}
});<template>
<PhoneInput
:model-value="userStore.phoneDigits"
:country="userStore.country"
@update:model-value="userStore.setPhoneDigits"
@country-change="userStore.setCountry($event.id)"
/>
</template>
<script setup>
const userStore = useUserStore();
</script>Multi-step Form
<template>
<div>
<div v-if="step === 1">
<h2>Step 1: Contact Info</h2>
<PhoneInput v-model="formData.phone" country="US" @validation-change="phoneValid = $event" />
<button @click="nextStep" :disabled="!phoneValid">Next</button>
</div>
<div v-if="step === 2">
<h2>Step 2: Verification</h2>
<p>We'll send a code to: {{ formData.phone }}</p>
<button @click="prevStep">Back</button>
<button @click="submit">Send Code</button>
</div>
</div>
</template>
<script setup>
const step = ref(1);
const phoneValid = ref(false);
const formData = reactive({
phone: ''
});
const nextStep = () => {
if (phoneValid.value) step.value++;
};
const prevStep = () => {
step.value--;
};
const submit = async () => {
// Send verification code
};
</script>i18n Integration
<template>
<PhoneInput v-model="phone" :locale="$i18n.locale" :placeholder="$t('phone.placeholder')" />
</template>
<script setup>
const { locale, t } = useI18n();
const phone = ref('');
</script>π― Auto-imports
The following are automatically imported (until disabled in nuxt.config.ts):
Components
PhoneInputβ Main phone input component
Directives
vPhoneMaskβ Phone mask directive
Helpers
vPhoneMaskSetCountryβ Programmatically set country for directivePMaskHelpersβ Utility functions for phone masks like:getFlagEmojicountPlaceholdersformatDigitsWithMappickMaskVariantremoveCountryCodePrefix- And more...
Read more about helpers in the Utility Functions of @desource/phone-mask README.
Types
All TypeScript types from @desource/phone-mask-vue
π Migration from Vue Plugin
If you're migrating from the Vue plugin:
Before:
// main.ts
import PhoneMaskPlugin from '@desource/phone-mask-vue';
import '@desource/phone-mask-vue/style.css';
app.use(PhoneMaskPlugin);After:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@desource/phone-mask-nuxt']
});No changes needed in your components!
π¦ What's Included
PhoneInputcomponent (auto-imported)vPhoneMaskdirective (auto-imported)- Default styles (auto-imported, can be disabled)
- TypeScript definitions (auto-imported)
- Utility functions (auto-imported)
π Related
- @desource/phone-mask β Core library
- @desource/phone-mask-vue β Vue 3 component
π License
MIT Β© 2026 DeSource Labs
