# Simple Phone Mask

A lightweight and customizable phone number input mask with country flags, search, validation and dark theme.

[![NPM Version](https://img.shields.io/npm/v/simple-phone-mask.svg)](https://www.npmjs.com/package/simple-phone-mask)
[![GitHub License](https://img.shields.io/github/license/mykulyncom/simple-phone-mask)](https://github.com/mykulyncom/simple-phone-mask/blob/main/LICENSE)

## Features

-   🌍 Country flag display with optional country selection
-   🔍 Search field inside the country dropdown
-   🌙 Dark theme support
-   ✅ Built-in phone number validation
-   ⭐ Preferred (pinned) countries at the top of the list
-   🌐 Automatic country detection by IP address
-   📱 Automatic phone number formatting based on country
-   🎯 Custom mask patterns support
-   🚀 No dependencies
-   📦 Lightweight

## Demo

Check out the <a href="https://mykulyn.com/simple-phone-mask/" target="_blank" rel="noopener noreferrer">online demo</a> to see it in action!

## Installation

### NPM

```bash
npm install simple-phone-mask
```

### CDN

```html
<!-- JavaScript -->
<script src="https://unpkg.com/simple-phone-mask@1.0.5/dist/simple-phone-mask.min.js"></script>

<!-- CSS -->
<link href="https://unpkg.com/simple-phone-mask@1.0.5/dist/simple-phone-mask.min.css" rel="stylesheet" />
```

## Usage

### HTML

```html
<input type="tel" id="phone" />
```

### JavaScript

```javascript
// Basic usage with default settings (Ukraine)
new SimplePhoneMask('#phone');

// With country flag and selection
new SimplePhoneMask('#phone', {
	countryCode: 'UA',
	showFlag: true,
	allowCountrySelect: true,
});

// With flag but without country selection
new SimplePhoneMask('#phone', {
	countryCode: 'US',
	showFlag: true,
	allowCountrySelect: false,
});

// Without flag
new SimplePhoneMask('#phone', {
	countryCode: 'PL',
	showFlag: false,
});

// With custom mask pattern
new SimplePhoneMask('#phone', {
	countryCode: '+48',
	maskPattern: '___ ___ ___',
	showFlag: true,
	allowCountrySelect: false,
});

// Auto-detect country by IP
new SimplePhoneMask('#phone', {
	detectIP: true,
	showFlag: true,
	allowCountrySelect: true,
});

// Dark theme
new SimplePhoneMask('#phone', {
	countryCode: 'UA',
	showFlag: true,
	allowCountrySelect: true,
	darkTheme: true,
});

// With search in dropdown
new SimplePhoneMask('#phone', {
	countryCode: 'UA',
	showFlag: true,
	allowCountrySelect: true,
	showSearch: true,
});

// With validation
new SimplePhoneMask('#phone', {
	countryCode: 'UA',
	showFlag: true,
	validate: true,
	onValidate: (isValid, value) => {
		console.log('Valid:', isValid, 'Value:', value);
	},
});

// Programmatic validation (e.g. on form submit)
const mask = new SimplePhoneMask('#phone', {
	countryCode: 'UA',
	validate: true,
});
document.querySelector('form').addEventListener('submit', (e) => {
	if (!mask.validate()) {
		e.preventDefault();
	}
});

// Preferred (pinned) countries
new SimplePhoneMask('#phone', {
	countryCode: 'UA',
	showFlag: true,
	allowCountrySelect: true,
	preferredCountries: ['UA', 'US', 'GB', 'PL'],
});
```

## Options

| Option               | Type       | Default | Description                                                                                                    |
| -------------------- | ---------- | ------- | -------------------------------------------------------------------------------------------------------------- |
| `countryCode`        | `string`   | `"UA"`  | Country code (e.g., `'UA'`, `'US'`) or phone code (e.g., `'+380'`, `'+1'`)                                    |
| `maskPattern`        | `string`   | `null`  | Custom mask pattern (overrides default country mask)                                                           |
| `showFlag`           | `boolean`  | `true`  | Show country flag button                                                                                       |
| `allowCountrySelect` | `boolean`  | `true`  | Allow country selection from dropdown                                                                          |
| `detectIP`           | `boolean`  | `false` | Auto-detect country by IP. Overrides `countryCode` when enabled.                                               |
| `darkTheme`          | `boolean`  | `false` | Enable dark theme for the dropdown                                                                             |
| `showSearch`         | `boolean`  | `true`  | Show a search field inside the dropdown (only when `allowCountrySelect: true`)                                 |
| `validate`           | `boolean`  | `false` | Enable phone validation — shows valid/invalid state on blur and creates a hint message below the input         |
| `onValidate`         | `function` | `null`  | Callback fired on every validation check. Receives `(isValid: boolean, value: string)`                        |
| `errorMessage`       | `string`   | `'Please enter a complete phone number.'` | Custom message shown when number is incomplete |
| `successMessage`     | `string`   | `'✓ Looks good!'` | Custom message shown when number is valid |
| `preferredCountries` | `string[]` | `[]`    | Array of ISO country codes to pin at the top of the dropdown (e.g., `['UA', 'US', 'GB']`)                     |

## Methods

| Method       | Returns   | Description                                                                 |
| ------------ | --------- | --------------------------------------------------------------------------- |
| `validate()` | `boolean` | Runs validation on all matched inputs and returns `true` if all are valid   |
| `destroy()`  | `void`    | Removes all event listeners and cleans up                                   |

## Changelog

### 1.0.5
- ✨ Added **dark theme** (`darkTheme: true`)
- 🔍 Added **search field** in dropdown (`showSearch: true`)
- ✅ Added **validation** with inline message and `onValidate` callback
- ⭐ Added **preferred countries** pinned at the top (`preferredCountries: ['UA', 'US']`)
- 🐛 Minor dropdown UX improvements (border-radius, selected highlight, focus restore)

### 1.0.4
- Initial public release

## Supported Countries

The library supports phone number formatting for 50+ countries including:

-   🇺🇦 Ukraine (+380)
-   🇺🇸 United States (+1)
-   🇬🇧 United Kingdom (+44)
-   🇩🇪 Germany (+49)
-   🇫🇷 France (+33)
-   🇵🇱 Poland (+48)
-   And many more…

## Browser Support

-   Chrome (latest)
-   Firefox (latest)
-   Safari (latest)
-   Edge (latest)
-   Opera (latest)

## Contributing

1. Fork it!
2. Create your feature branch: `git checkout -b feature/my-new-feature`
3. Commit your changes: `git commit -am 'Add some feature'`
4. Push to the branch: `git push origin feature/my-new-feature`
5. Submit a pull request

## License

This project is licensed under the MIT License — see the [LICENSE](LICENSE) file for details.

## Author

Created by [Serhii Mykulyn](https://github.com/mykulyncom)

## Support

If you found this project useful, please consider giving it a ⭐️ on [GitHub](https://github.com/mykulyncom/simple-phone-mask)!