A powerful React component for international phone numbers and usernames in one field. Supports 240+ countries, optional country selector, phone formatting, RTL, and is built for performance with lazy loading and code-splitting.
npm install react-intl-phone-username-input
Everything you need for international phone and username input in one reusable component.
Single input for phone or username/email; mode can be fixed or hybrid (auto-detect).
240+ countries with flags and dial codes; optional dropdown to choose country.
Phone mode for numbers only; hybrid accepts text or phone and formats when it looks like a number.
Custom dropdown (search + keyboard) or native select; auto choice on mobile vs desktop.
Optional as-you-type formatting via libphonenumber-js for proper phone number display.
Lazy-loaded country list and dynamically imported selectors; memoized components; small initial bundle.
Full TypeScript support with typed props and options out of the box.
ARIA attributes, keyboard navigation in custom dropdown, semantic markup.
Built-in right-to-left layout and text direction support for international audiences.
Choose the mode that fits your use case. Switch between phone-only and hybrid modes effortlessly.
Strictly phone number input with formatting. Perfect for forms that only need phone numbers.
Accepts usernames, emails, OR phone numbers. Smart detection formats phones, preserves text.
Drop it into your React project and start collecting phone numbers or usernames immediately.
import { IntlPhoneUsernameInput } from "react-intl-phone-username-input";
import "react-intl-phone-username-input/style.css";
import { useState } from "react";
export default function App() {
const [value, setValue] = useState("");
return (
<IntlPhoneUsernameInput
value={value}
onChange={setValue}
options={{
mode: "phone",
defaultCountry: "IN",
multiCountry: true,
enableFlag: true,
}}
placeholder="Enter phone number"
/>
);
}
<IntlPhoneUsernameInput
value={value}
onChange={setValue}
options={{
mode: "phone",
defaultCountry: "US",
multiCountry: true,
enforceCustomSelect: true,
customSelect: {
showFlag: true,
showDialCode: true,
enableSearch: true,
searchPlaceholder: "Search countries...",
},
}}
placeholder="Use ↑↓ and Enter in the dropdown"
/>
<IntlPhoneUsernameInput
value={value}
onChange={setValue}
options={{
mode: "hybrid",
defaultCountry: "US",
enableFlag: true,
}}
placeholder="Enter username, email, or phone"
/>
<IntlPhoneUsernameInput
value={value}
onChange={setValue}
options={{
mode: "phone",
direction: "rtl",
defaultCountry: "AE",
multiCountry: true,
}}
placeholder="أدخل رقم الهاتف"
/>
Fully typed props and options for complete control over behavior and appearance.
| Prop | Type | Required | Description |
|---|---|---|---|
| value | string | Yes | Current input value (controlled) |
| onChange | (value: string) => void | Yes | Called when the value changes |
| onChangeSelect | (change) => void | No | Called with {countryCode, dialCode, label, name, source} when country changes |
| options | object | No | Configuration object; see Options below |
| className | string | No | Class name for the root wrapper |
| selectFieldName | string | No | Field name for country selector |
| placeholder | string | No | Input placeholder |
| Option | Type | Default | Description |
|---|---|---|---|
| mode | "phone" | "hybrid" | "hybrid" | Phone: strictly numbers; Hybrid: accepts text or phone |
| defaultCountry | string | "IN" | Default country (ISO code, e.g., "US", "IN") |
| multiCountry | boolean | false | Show country selector dropdown |
| format | boolean | true | Format phone number as you type |
| enableFlag | boolean | true | Show flag in single-country mode |
| hideDialCode | boolean | false | Hide dial code in input |
| enforceCustomSelect | boolean | false | Always use custom dropdown |
| enforceHtmlSelect | boolean | false | Always use native select |
| flagBaseUrl | string | "https://flagcdn.com" | Base URL for flag SVGs |
| direction | "ltr" | "rtl" | "ltr" | Text/layout direction |
| preferredCountries | string[] | [] | Countries to show first, e.g., ["US", "CA"] |
| highlightCountries | string[] | [] | Countries to pin at the top |
Flexible styling options with CSS class overrides and custom theming support.
<IntlPhoneUsernameInput
className="my-form-field"
value={value}
onChange={setValue}
/>
<IntlPhoneUsernameInput
value={value}
onChange={setValue}
options={{
defaultCountry: "IN",
multiCountry: true,
classes: {
intlPhoneUsernameInputWrapper: "my-wrapper",
input_box: "my-input",
flag_container: "my-flag-container",
custom_select: {
select_container: "my-dropdown",
country_option: "my-option",
search_input: "my-search",
},
html_select: {
html_select_container: "my-native-select",
select_overlay: "my-overlay",
},
},
}}
/>
For complete styling documentation and best practices, check out the STYLING.md documentation file.
Access the same validation and formatting helpers from libphonenumber-js that the component uses internally.
import {
isValidPhoneNumber,
isPossiblePhoneNumber,
parsePhoneNumber,
parsePhoneNumberWithError,
formatIncompletePhoneNumber,
AsYouType,
getExampleNumber,
examples,
} from "react-intl-phone-username-input";
// Usage examples
const valid = isValidPhoneNumber('+1 (555) 123-4567');
const parsed = parsePhoneNumber('+91 98765 43210');
const formatted = formatIncompletePhoneNumber('5551234');
Optimized loading strategy ensures minimal initial bundle size and fast page loads.
Country list and selector components load only when needed, keeping initial bundle small.
Works immediately with minimal list; full features available asynchronously.
For detailed build size analysis and performance metrics:
View Build Size Analysis →