lite-phone-input
v0.5.0
Published
Lightweight phone input with formatting, validation, and emoji flags — ~13KB gzipped
Maintainers
Readme
lite-phone-input
Lightweight phone input with format-as-you-type, validation, and emoji flags. ~13KB gzipped total — zero runtime dependencies.
Why lite-phone-input?
| | lite-phone-input | intl-tel-input | |---|---|---| | JS bundle | ~13KB (includes formatting + validation) | ~15KB + ~260KB utils | | Flag assets | Emoji (0KB) | Webp sprites (30–66KB) | | Dependencies | 0 | Flag sprites + optional utils | | Formatting | Built-in | Requires utils bundle | | Validation | Built-in | Requires utils bundle |
Features
- ~13KB gzipped (JS + country data) — includes formatting AND validation
- Emoji flags computed from ISO code at runtime (zero image cost)
- Format-as-you-type with per-country masks (~240 countries)
- Per-country length validation with rich error data
- TypeScript-first with full type definitions
- Framework adapters — Vanilla JS, React, Preact
- Accessible — WCAG 2.1 AA, ARIA combobox pattern, keyboard navigation
- SSR-safe — no browser API calls at module level
Installation
npm install lite-phone-inputQuick Start
Vanilla JS
import { PhoneInput } from 'lite-phone-input/vanilla';
import 'lite-phone-input/styles';
const phone = PhoneInput.mount(document.getElementById('phone'), {
defaultCountry: 'US',
separateDialCode: true,
onChange(e164, country, validation) {
console.log(e164); // '+12025551234'
console.log(country.code); // 'US'
console.log(validation.valid); // true
},
});React
import { useRef } from 'react';
import { PhoneInput } from 'lite-phone-input/react';
import 'lite-phone-input/styles';
function MyForm() {
const phoneRef = useRef(null);
return (
<PhoneInput
ref={phoneRef}
defaultCountry="US"
separateDialCode
initialValue="+12025551234"
onChange={(e164) => console.log(e164)}
name="phone"
aria-label="Phone number"
/>
);
}Preact
import { PhoneInput } from 'lite-phone-input/preact';
import 'lite-phone-input/styles';Same API as React. Uses preact/hooks directly — no preact/compat required.
CDN / Script Tag
<link rel="stylesheet" href="https://unpkg.com/lite-phone-input/dist/styles.css">
<script src="https://unpkg.com/lite-phone-input/dist/vanilla/index.global.js"></script>
<script>
const phone = LitePhoneInput.PhoneInput.mount(document.getElementById('phone'), {
defaultCountry: 'US',
});
</script>Geo IP Lookup
Auto-detect the user's country at mount time using any geo-IP service. The lookup runs once, and the result is ignored if the user has already interacted with the widget.
const phone = PhoneInput.mount(document.getElementById('phone'), {
defaultCountry: 'US',
geoIpLookup: (callback) => {
// Cloudflare (free, no API key)
fetch('/cdn-cgi/trace')
.then(res => res.text())
.then(text => {
const match = text.match(/loc=(\w+)/);
callback(match ? match[1] : null);
})
.catch(() => callback(null));
},
});// Alternative: ipapi.co
geoIpLookup: (callback) => {
fetch('https://ipapi.co/json/')
.then(res => res.json())
.then(data => callback(data.country_code))
.catch(() => callback(null));
}Documentation
| Guide | Description | |---|---| | Getting Started | Installation and first render | | Vanilla JS Guide | Mounting, methods, callbacks | | React Guide | Usage, ref methods, form libraries | | Preact Guide | Preact-specific setup | | API Reference | All options, methods, and types | | Styling & Theming | CSS variables, BEM classes, dark mode | | Validation | Validation model and error messages | | Form Integration | Hidden inputs, RHF, Formik | | Core Utilities | Headless/server-side functions | | Accessibility | ARIA patterns, keyboard navigation | | Advanced Topics | SSR, RTL, i18n, portals | | Migration from intl-tel-input | Comparison and migration guide |
Browser Support
Chrome 80+, Firefox 80+, Safari 14+, Edge 80+. No IE support, no polyfills needed.
Contributing
See CONTRIBUTING.md for development setup and guidelines.
Changelog
See CHANGELOG.md for release history.
