A multi-region phone number normalisation toolkit for Vue 3 and standalone usage. The package builds on top of libphonenumber-js to deliver:
- 🔄 Normalisation – converts messy, localised strings into consistent E.164 / international / national outputs.
- ✅ Validation – configurable checks for blocklists, country allow-lists, length constraints, and extension policies.
- 🧠 Region fallback logic – automatic detection with graceful degradation through default + fallback country lists.
- 🧩 Vue bindings – composable + directive for instant drop-in formatting within apps.
- 🧪 TypeScript-first – shared types for options, blocklists, and result shapes.
npm install @cartoonclouds/phone-normaliserimport { normalisePhone } from '@cartoonclouds/phone-normaliser'
const result = normalisePhone('+44 (0) 7700 900123 ext 9', {
defaultCountry: 'GB',
format: 'INTERNATIONAL',
})
console.log(result.phone) // +44 7700 900123
console.log(result.metadata.e164) // +447700900123
console.log(result.changes) // ['Converted unicode digits and separators.', 'Removed phone extension text.']import { validatePhone, PhoneValidationCodes } from '@cartoonclouds/phone-normaliser'
const checks = validatePhone('555 123', {
defaultCountry: 'US',
minLength: 10,
})
checks.forEach((check) => {
if (check.validationCode !== PhoneValidationCodes.VALID) {
console.warn(check.validationMessage)
}
})<script setup lang="ts">
import { usePhone } from '@cartoonclouds/phone-normaliser'
const { value, phone, valid, changes, apply } = usePhone('', {
autoFormat: true,
defaultCountry: 'US',
})
</script>
<template>
<label class="flow">
<span>Phone</span>
<input v-model="value" placeholder="Enter phone" />
<p v-if="!valid">{{ changes.join(', ') }}</p>
<button @click="apply">Apply formatted number</button>
<output>{{ phone }}</output>
</label>
</template><template>
<input
v-phone="{
autoFormat: true,
defaultCountry: 'KE',
previewSelector: '#phone-preview'
}"
placeholder="Enter phone"
/>
<div id="phone-preview"></div>
</template>The directive emits a directive:phone:normalised event when validation fails so forms can react immediately.
The published bundles target ES2018 syntax and ship ESM + CJS builds that align with the browserslist query >0.3%, last 2 versions, Firefox ESR, not dead. In practice that covers the latest Chrome, Edge, Firefox (stable + ESR) and Safari 14+ on macOS/iOS, along with their Android counterparts. The Vue directive lazily accesses document, so it also plays nicely with SSR setups where the DOM is unavailable during server renders.
defaultCountry– ISO country code used when no international prefix exists.fallbackCountries– ordered list used if parsing fails with the default.allowedCountries– restrict valid countries.blocklist–PhoneBlockConfigto block numbers, prefixes, or countries.format–'E.164' | 'INTERNATIONAL' | 'NATIONAL' | 'RFC3966'(default:E.164).stripExtensions– remove trailing extensions before parsing (default:true).- returns
PhoneNormResultwith parsed metadata and change codes.
Runs the same parsing logic but returns an array of ValidationResult objects with explicit PhoneValidationCodes covering:
- Empty input detection
- Invalid shape or length
- Blocklists and country allow-lists
- Extension policy breaches
Returns the underlying libphonenumber-js object without additional validation logic. Helpful if you only need to detect the country or format text yourself.
import { resolvePhoneNumber } from '@cartoonclouds/phone-normaliser'
const resolved = resolvePhoneNumber('07911 123456', {
defaultCountry: 'GB',
fallbackCountries: ['IE', 'US'],
})
if (resolved) {
console.log(resolved.phoneNumber.number) // +447911123456
console.log(resolved.usedFallback) // 'GB'
}Vue 3 Options API-friendly composable returning { value, phone, valid, changes, apply, validate }.
Directive that formats inputs as you type. Options mirror normalisePhone plus autoFormat, autoFormatEvents, and previewSelector for mirrored output.
| Command | Purpose |
|---|---|
npm run build |
Bundle CJS/ESM outputs (with declarations) via tsdown. |
npm run dev |
Watch and rebuild while hacking on src/ using tsdown. |
npm run test / npm run test:watch |
Execute the full Vitest suite once or in watch mode. |
npm run lint |
Apply ESLint autofixes. |
npm run docs |
Regenerate the Typedoc markdown under docs/. |
The docs/ directory is generated by Typedoc and lists every exported type, helper, and constant. Run npm run docs after changing the public API so README snippets and generated reference stay aligned.
All utilities and bindings are covered by Vitest suites.
cd packages/phone-normaliser
npm run testMIT © Cartoon Clouds