vue-a11y-phone
| Install | |
|---|---|
npm install vue-a11y-phone |
|
| Latest Version: | 1.1.1 |
| Vue: | 3 |
| License: | MIT |
| Last Updated: | May 18, 2026 |
| Links: | GitHub · npm |
vue-a11y-phone
Accessible international phone input for Vue 3. WCAG 2.2 AA, keyboard-first, screen-reader friendly.
- 9 KB JS + 1 KB CSS gzipped
- Zero runtime dependencies
- Vue 3.4+, peer-only
Install
npm install vue-a11y-phone
Usage
<template>
<Vue3PhoneInput v-model="phone" default-country="se" :preferred-countries="['se', 'no', 'dk']" />
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { Vue3PhoneInput } from 'vue-a11y-phone';
import 'vue-a11y-phone/vue-a11y-phone.css';
const phone = ref('');
</script>
Global registration
import { createApp } from 'vue';
import VueA11yPhone from 'vue-a11y-phone';
import 'vue-a11y-phone/vue-a11y-phone.css';
const app = createApp(App);
app.use(VueA11yPhone);
Then use <vue3-phone-input> in any template.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue |
string |
'' |
Phone number (full international format with dial code) |
defaultCountry |
string |
'us' |
Default country ISO2 code (lowercase) |
preferredCountries |
string[] |
[] |
Countries shown at the top of the dropdown |
onlyCountries |
string[] |
[] |
Only show these countries |
ignoredCountries |
string[] |
[] |
Hide these countries from the dropdown |
disabled |
boolean |
false |
Disable the input and dropdown |
inputId |
string |
— | Native input id attribute |
name |
string |
'phone' |
Native input name attribute |
required |
boolean |
false |
Native input required attribute |
placeholder |
string |
— | Native input placeholder |
autocomplete |
string |
'tel' |
Native input autocomplete attribute |
invalid |
boolean |
false |
Marks the input as invalid (styling + aria-invalid) |
ariaDescribedby |
string |
— | Additional aria-describedby ID(s) for the input |
inputLabel |
string |
'Phone number' |
aria-label for the phone input |
countryLabel |
string |
'Select country code' |
aria-label for the country selector button |
searchPlaceholder |
string |
'Search country...' |
Placeholder and aria-label for the country search |
searchResultsLabel |
(count: number) => string |
— | Custom function for screen reader search result announcements |
formatDisplay |
(digits, iso2) => string |
— | Custom display formatter. Overrides built-in national formatting. Model value stays unformatted |
useNationalFormat |
boolean |
true |
Apply built-in country-aware grouping (e.g. 070 123 45 67 for SE) when no formatDisplay is provided |
stripLeadingZero |
boolean |
true |
Strip a single leading 0 from typed input (common in countries with a trunk prefix) |
showNativeNames |
boolean |
false |
Show each country's native name next to the English name in the dropdown |
maxLength |
number |
per-country | Max digits in the national number. Defaults to the per-country max (or 15) |
styleClasses |
string | string[] | Record<string, boolean> |
— | Custom CSS classes for the wrapper element |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue |
string |
Phone number changed (full international format) |
update:valid |
boolean |
Validity changed (length within country's min/max). Use with v-model:valid |
country-changed |
Country |
Selected country changed |
open |
— | Dropdown opened |
close |
— | Dropdown closed |
focus |
FocusEvent |
Phone input received focus |
blur |
FocusEvent |
Phone input lost focus |
Exposed methods
const phoneRef = ref<InstanceType<typeof Vue3PhoneInput>>();
phoneRef.value?.focus();
phoneRef.value?.blur();
phoneRef.value?.validate(); // boolean — current validity
Helpers
The package also exports utilities for working with phone numbers outside the component:
import {
allCountries,
formatNational,
formatSwedishPhone,
getCountryMeta,
getNativeName,
isValidNationalNumber
} from 'vue-a11y-phone';
formatNational('se', '701234567'); // → "70 123 45 67"
formatNational('us', '5551234567'); // → "555 123 4567"
isValidNationalNumber('se', '7012345'); // → true (7+ digits)
getCountryMeta('gb'); // → { minLength, maxLength, groups }
getNativeName('de'); // → "Deutschland"
Theming
All styles use CSS custom properties. Override any --v3pi-* variable to customize:
.v3pi {
--v3pi-border-color: #ced4da;
--v3pi-border-radius: 0.375rem;
--v3pi-bg: #ffffff;
--v3pi-font-family: inherit;
--v3pi-font-size: 1rem;
--v3pi-padding-y: 0.375rem;
--v3pi-padding-x: 0.75rem;
--v3pi-focus-color: #0d6efd;
--v3pi-focus-width: 0.25rem;
--v3pi-error-color: #dc3545;
--v3pi-hover-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
--v3pi-dropdown-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.15);
--v3pi-item-hover-bg: #f8f9fa;
--v3pi-item-selected-bg: #e9ecef;
--v3pi-divider-color: #dee2e6;
--v3pi-disabled-bg: #e9ecef;
--v3pi-disabled-opacity: 0.65;
}
Accessibility
This component is built for WCAG 2.2 AA compliance:
- Native
<input type="tel">— no fake inputs or masking - Real
<button>for the country selector witharia-expanded,aria-haspopup, andaria-controls - WAI-ARIA combobox pattern for country search (
role="combobox",aria-autocomplete,aria-activedescendant) role="listbox"androle="option"witharia-selectedfor country listaria-live="polite"region announcing search result count to screen readersaria-labelon the phone input, country button, and search inputaria-describedbylinking the phone input to a country hint for screen readersaria-invalidsupport for validation states- Full keyboard navigation: Arrow keys, Enter, Escape, Tab
:focus-visibleoutlines on all interactive elements- Unique IDs per instance — safe to use multiple components on one page
Keyboard navigation
DOM focus stays on the search input while the dropdown is open; only aria-activedescendant moves through the options. This follows the WAI-ARIA APG combobox pattern.
| Key | Context | Action |
|---|---|---|
Arrow Down / Up |
Country button | Opens dropdown |
Enter / Space |
Country button | Opens dropdown |
Arrow Down / Up |
Search input | Highlights next/previous country |
Home / End |
Search input | Highlights first/last country |
Enter |
Search input | Selects highlighted country |
Escape |
Dropdown open | Closes dropdown, returns focus to button |
Tab |
Search input | Closes dropdown and moves focus to next focusable element |
TypeScript
Full type definitions are included. Import types directly:
import type { Country, CountryMeta, Vue3PhoneInputProps, Vue3PhoneInputEmits } from 'vue-a11y-phone';
Browser support
The component targets evergreen browsers (Chrome, Firefox, Safari, Edge). It uses Intl.DisplayNames for native country names — older browsers fall back to the English name.
Contributing
Issues and pull requests welcome. See CONTRIBUTING.md.
License
MIT © Rickard Lindbom
Related Packages
Accessible international phone input with country calling code, shipped as a fra...
Modern phone number formatting library with React/Vue components, TypeScript sup...
A comprehensive set of Vue 3 directives for building accessible web applications...
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 1.1.1 | ^3.4.0 | MIT | |
| 1.1.0 | ^3.4.0 | MIT | |
| 1.0.1 | ^3.4.0 | MIT | |
| 1.0.0 | ^3.4.0 | MIT |