{"id":30570425,"url":"https://github.com/toozuuu/ngxsmk-tel-input","last_synced_at":"2025-08-28T20:09:06.447Z","repository":{"id":309704642,"uuid":"1037246471","full_name":"toozuuu/ngxsmk-tel-input","owner":"toozuuu","description":"International phone input for Angular 17–19. Flags, smart formatting + libphonenumber validation. E.164 output. SSR-safe. i18n/RTL. Standalone CVA.","archived":false,"fork":false,"pushed_at":"2025-08-22T20:13:09.000Z","size":13027,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-22T22:48:27.629Z","etag":null,"topics":["angular","angular-17","angular-18","angular-19","angular-components","angular-forms","i18n","intl-tel-input","libphonenumber","ngx","phone","phone-number","reactive-forms","rtl","ssr","standalone-components","telephone","template-driven-forms","ui-component"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/toozuuu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-13T09:32:29.000Z","updated_at":"2025-08-22T20:13:13.000Z","dependencies_parsed_at":"2025-08-13T11:41:33.580Z","dependency_job_id":"1f498d07-9001-434f-80fd-f5df58c0491e","html_url":"https://github.com/toozuuu/ngxsmk-tel-input","commit_stats":null,"previous_names":["toozuuu/ngx-tel-input"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/toozuuu/ngxsmk-tel-input","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toozuuu%2Fngxsmk-tel-input","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toozuuu%2Fngxsmk-tel-input/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toozuuu%2Fngxsmk-tel-input/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toozuuu%2Fngxsmk-tel-input/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/toozuuu","download_url":"https://codeload.github.com/toozuuu/ngxsmk-tel-input/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/toozuuu%2Fngxsmk-tel-input/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272547274,"owners_count":24953436,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-28T02:00:10.768Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","angular-17","angular-18","angular-19","angular-components","angular-forms","i18n","intl-tel-input","libphonenumber","ngx","phone","phone-number","reactive-forms","rtl","ssr","standalone-components","telephone","template-driven-forms","ui-component"],"created_at":"2025-08-28T20:03:00.699Z","updated_at":"2025-08-28T20:09:06.432Z","avatar_url":"https://github.com/toozuuu.png","language":"TypeScript","funding_links":[],"categories":["Third Party Components"],"sub_categories":["Form Controls"],"readme":"# ngxsmk-tel-input\n\nAn Angular **telephone input** component with country dropdown, flags, and robust validation/formatting.\nWraps [`intl-tel-input`](https://github.com/jackocnr/intl-tel-input) for the UI and [`libphonenumber-js`](https://github.com/catamphetamine/libphonenumber-js) for parsing/validation. Implements `ControlValueAccessor` so it plugs into Angular Forms.\n\n\u003e Emits **E.164** by default (e.g. `+14155550123`). SSR‑safe via lazy browser‑only import.\n\n---\n\n## Screenshots\n\n\u003cp align=\"left\"\u003e\n  \u003cimg src=\"https://unpkg.com/ngxsmk-tel-input@latest/docs/valid.png\" alt=\"Angular international phone input - valid\" width=\"420\" /\u003e\n  \u0026nbsp;\u0026nbsp;\n  \u003cimg src=\"https://unpkg.com/ngxsmk-tel-input@latest/docs/invalid.png\" alt=\"Angular international phone input - Invalid\" width=\"420\" /\u003e\n\u003c/p\u003e\n\n---\n\n## ✨ Features\n\n* Country dropdown with flags\n* E.164 output (display can be national with `nationalMode`)\n* Reactive \u0026 template‑driven Forms support (CVA)\n* Built‑in validation using libphonenumber‑js\n* SSR‑friendly (no `window` on the server)\n* Easy theming via CSS variables\n* Nice UX options: label/hint/error text, sizes, variants, clear button, autofocus, select-on-focus\n* New: Masking \u0026 caret-friendly as-you-type formatting (optional)\n* New: Format only when valid (formatWhenValid) and lock once valid (lockWhenValid) to prevent extra digits\n\n---\n\n## ✅ Requirements\n\n* Angular **17 – 19**\n* Node **18** or **20**\n\n\u003e Library `peerDependencies` target Angular `\u003e=17 \u003c20`. Your app can be 17, 18, or 19.\n\n---\n\n## 📦 Install\n\n```bash\nnpm i ngxsmk-tel-input intl-tel-input libphonenumber-js\n```\n\n### Add styles \u0026 flag assets (in your **app**, not the library)\n\nUpdate your app’s `angular.json`:\n\n```jsonc\n{\n  \"projects\": {\n    \"your-app\": {\n      \"architect\": {\n        \"build\": {\n          \"options\": {\n            \"styles\": [\n              \"node_modules/intl-tel-input/build/css/intlTelInput.css\"\n            ],\n            \"assets\": [\n              { \"glob\": \"**/*\", \"input\": \"node_modules/intl-tel-input/build/img\", \"output\": \"assets/intl-tel-input/img\" }\n            ]\n          }\n        }\n      }\n    }\n  }\n}\n```\n\nOptional override to ensure flags resolve (e.g., Vite/Angular 17+): add to your global styles\n\n```css\n.iti__flag { background-image: url(\"/assets/intl-tel-input/img/flags.png\"); }\n@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {\n  .iti__flag { background-image: url(\"/assets/intl-tel-input/img/flags@2x.png\"); }\n}\n```\n\nRestart the dev server after changes.\n\n---\n\n## 🚀 Quick start (Reactive Forms)\n\n```ts\n// app.component.ts\nimport { Component, inject } from '@angular/core';\nimport { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';\nimport { JsonPipe } from '@angular/common';\nimport { NgxsmkTelInputComponent, IntlTelI18n, CountryMap } from 'ngxsmk-tel-input';\n\n@Component({\n  selector: 'app-root',\n  standalone: true,\n  imports: [ReactiveFormsModule, NgxsmkTelInputComponent, JsonPipe],\n  template: `\n    \u003cform [formGroup]=\"fg\" style=\"max-width:420px;display:grid;gap:12px\"\u003e\n        \u003cngxsmk-tel-input\n        formControlName=\"phone\"\n        label=\"Phone\"\n        hint=\"Include area code\"\n        dir=\"ltr\"\n        [initialCountry]=\"'US'\"\n        [preferredCountries]=\"['US','GB','AU']\"\n        [i18n]=\"enLabels\"\n        [localizedCountries]=\"enCountries\"\n        [separateDialCode]=\"true\"         \u003c!-- dial code after the flag --\u003e\n        [formatWhenValid]=\"'typing'\"      \u003c!-- live mask only when valid --\u003e\n        [lockWhenValid]=\"true\"            \u003c!-- stop extra digits once valid --\u003e\n      \u003e\u003c/ngxsmk-tel-input\u003e\n\n      \u003cpre\u003eValue: {{ fg.value | json }}\u003c/pre\u003e\n    \u003c/form\u003e\n  `\n})\nexport class AppComponent {\n  private readonly fb = inject(FormBuilder);\n  fg = this.fb.group({ phone: ['', Validators.required] });\n\n  // English UI labels (dropdown/search/ARIA)\n  enLabels: IntlTelI18n = {\n    selectedCountryAriaLabel: 'Selected country',\n    countryListAriaLabel: 'Country list',\n    searchPlaceholder: 'Search country',\n    zeroSearchResults: 'No results',\n    noCountrySelected: 'No country selected'\n  };\n\n  // Optional: only override the names you care about\n  enCountries: CountryMap = {\n    US: 'United States',\n    GB: 'United Kingdom',\n    AU: 'Australia',\n    CA: 'Canada'\n  };\n}\n\n```\n\n**Value semantics:** the form control value is **E.164** (e.g., `+14155550123`) when valid, or `null` when empty/invalid.\n\n---\n\n## 📝 Template‑driven usage\n\n```html\n\u003cform #f=\"ngForm\"\u003e\n  \u003cngxsmk-tel-input name=\"phone\" [(ngModel)]=\"phone\"\u003e\u003c/ngxsmk-tel-input\u003e\n\u003c/form\u003e\n\u003c!-- phone is an E.164 string or null --\u003e\n```\n\n---\n\n## 🈺 Localization \u0026 RTL\n\nYou can localize the dropdown/search labels and override country names.\n\n\u003cimg src=\"https://unpkg.com/ngxsmk-tel-input@latest/docs/kr.png\" alt=\"Angular international phone input - Korean Localization \u0026 RTL\" width=\"420\" /\u003e\n\nKorean example\n\n```ts\n\n\u003cngxsmk-tel-input\n  [initialCountry]=\"'KR'\"\n  [preferredCountries]=\"['KR','US','JP']\"\n  [i18n]=\"koLabels\"\n  [localizedCountries]=\"koCountries\"\u003e\n\u003c/ngxsmk-tel-input\u003e\n\n// in component\nkoLabels = {\n  selectedCountryAriaLabel: '선택한 국가',\n  countryListAriaLabel: '국가 목록',\n  searchPlaceholder: '국가 검색',\n  zeroSearchResults: '결과 없음',\n  noCountrySelected: '선택된 국가 없음'\n};\n\nkoCountries = {\n  KR: '대한민국',\n  US: '미국',\n  JP: '일본',\n  CN: '중국'\n};\n\n```\n\nArabic + RTL example\n\n```ts\n\u003cngxsmk-tel-input\n  dir=\"rtl\"\n  label=\"الهاتف\"\n  hint=\"اكتب رمز المنطقة\"\n  [initialCountry]=\"'AE'\"\n  [preferredCountries]=\"['AE','SA','EG']\"\n  [i18n]=\"arLabels\"\n  [localizedCountries]=\"arCountries\"\n  [dropdownAttachToBody]=\"false\"  \u003c!-- so popup inherits rtl from host --\u003e\n\u003e\u003c/ngxsmk-tel-input\u003e\n\n```\n\n\n## ⚙️ API\n\n### Inputs\n\n| Name                   | Type                                        | Default                 | Description                                                                                |\n|------------------------|---------------------------------------------|-------------------------|--------------------------------------------------------------------------------------------|\n| `initialCountry`       | `CountryCode \\| 'auto'`                     | `'US'`                  | Starting country. `'auto'` uses geoIp stub (`US` by default).                              |\n| `preferredCountries`   | `CountryCode[]`                             | `['US','GB']`           | Pin these at the top.                                                                      |\n| `onlyCountries`        | `CountryCode[]`                             | —                       | Limit selectable countries.                                                                |\n| `nationalMode`         | `boolean`                                   | `false`                 | If `true`, **display** national format in the input. Value still emits E.164.              |\n| `separateDialCode`     | `boolean`                                   | `false`                 | Show dial code outside the input.                                                          |\n| `allowDropdown`        | `boolean`                                   | `true`                  | Enable/disable dropdown.                                                                   |\n| `placeholder`          | `string`                                    | `'Enter phone number'`  | Input placeholder.                                                                         |\n| `autocomplete`         | `string`                                    | `'tel'`                 | Native autocomplete.                                                                       |\n| `disabled`             | `boolean`                                   | `false`                 | Disable the control.                                                                       |\n| `label`                | `string`                                    | —                       | Optional floating label text.                                                              |\n| `hint`                 | `string`                                    | —                       | Helper text below the control.                                                             |\n| `errorText`            | `string`                                    | —                       | Custom error text.                                                                         |\n| `size`                 | `'sm' \\| 'md' \\| 'lg'`                      | `'md'`                  | Control height/typography.                                                                 |\n| `variant`              | `'outline' \\| 'filled' \\| 'underline'`      | `'outline'`             | Visual variant.                                                                            |\n| `showClear`            | `boolean`                                   | `true`                  | Show a clear (×) button when not empty.                                                    |\n| `autoFocus`            | `boolean`                                   | `false`                 | Focus on init.                                                                             |\n| `selectOnFocus`        | `boolean`                                   | `false`                 | Select all text on focus.                                                                  |\n| `formatOnBlur`         | `boolean`                                   | `true`                  | Pretty‑print on blur (national if `nationalMode`).                                         |\n| `showErrorWhenTouched` | `boolean`                                   | `true`                  | Show error styles only after blur.                                                         |\n| `dropdownAttachToBody` | `boolean`                                   | `true`                  | Attach dropdown to `\u003cbody\u003e` (avoids clipping/overflow).                                    |\n| `dropdownZIndex`       | `number`                                    | `2000`                  | Z‑index for dropdown panel.                                                                |\n| `i18n`                 | `IntlTelI18n`                               | —                       | Localize dropdown/search/ARIA labels.                                                      |\n| `localizedCountries`   | `Partial\u003cRecord\u003cCountryCode, string\u003e\u003e`      | —                       | Override country display names (ISO-2 keys).                                               |\n| `dir`                  | `'ltr' \\| 'rtl'`                            | `'ltr'`                 | Text direction for the control.                                                            |\n| `autoPlaceholder`      | `'off' \\| 'polite' \\| 'aggressive'`         | `'polite'`              | Example placeholders. Requires `utilsScript` unless `off`.                                 |\n| `utilsScript`          | `string`                                    | —                       | Path/URL to `utils.js` (needed for example placeholders).                                  |\n| `customPlaceholder`    | `(example: string, country: any) =\u003e string` | —                       | Transform the example placeholder.                                                         |\n| `clearAriaLabel`       | `string`                                    | `'Clear phone number'`  | ARIA label for the clear button.                                                           |\n| `lockWhenValid`        | `boolean`                                   | `true`                  | Prevent appending extra digits once the number is valid (editing/replacing still allowed). |\n\n\u003e `CountryCode` is the ISO‑2 uppercase code from `libphonenumber-js` (e.g. `US`, `GB`).\n\n### Outputs\n\n| Event            | Payload                                                    | Description                          |\n| ---------------- | ---------------------------------------------------------- | ------------------------------------ |\n| `countryChange`  | `{ iso2: CountryCode }`                                    | Fired when selected country changes. |\n| `validityChange` | `boolean`                                                  | Fired when validity flips.           |\n| `inputChange`    | `{ raw: string; e164: string \\| null; iso2: CountryCode }` | Emitted on every keystroke.          |\n\n### Public methods\n\n* `focus(): void`\n* `selectCountry(iso2: CountryCode): void`\n\n---\n\n## 🧠 Formatting \u0026 validity behavior\n\n* No formatting while invalid. As-you-type masking only starts when the digits form a valid number for the selected country.\n\n* Sri Lanka / “trunk 0”: a national format may include a leading 0 (e.g., 071…). The emitted E.164 always excludes it (+94 71…)—this is expected.\n\n* Lock when valid: with lockWhenValid enabled, once the number is valid, appending more digits is blocked (you can still delete/replace).\n\nFor rare patterns not covered by libphonenumber-js, the control falls back to raw digits (no forced mask) until it becomes valid.\n\n---\n\n\n## 🎨 Theming (CSS variables)\n\nOverride on the element or a parent container:\n\n```html\n\u003cngxsmk-tel-input style=\"\n  --tel-border:#cbd5e1;\n  --tel-ring:#22c55e;\n  --tel-radius:14px;\n  --tel-dd-item-hover: rgba(34,197,94,.12);\n  --tel-dd-z: 3000;\n\"\u003e\u003c/ngxsmk-tel-input\u003e\n```\n\nAvailable tokens:\n\n* Input: `--tel-bg`, `--tel-fg`, `--tel-border`, `--tel-border-hover`, `--tel-ring`, `--tel-placeholder`, `--tel-error`, `--tel-radius`, `--tel-focus-shadow`\n* Dropdown: `--tel-dd-bg`, `--tel-dd-border`, `--tel-dd-shadow`, `--tel-dd-radius`, `--tel-dd-item-hover`, `--tel-dd-search-bg`, `--tel-dd-z`\n\nDark mode: wrap in a `.dark` parent — tokens adapt automatically.\n\n---\n\n## ✔️ Validation patterns\n\n```html\n\u003cngxsmk-tel-input formControlName=\"phone\"\u003e\u003c/ngxsmk-tel-input\u003e\n\n\u003cdiv class=\"error\" *ngIf=\"fg.get('phone')?.hasError('required')\"\u003ePhone is required\u003c/div\u003e\n\u003cdiv class=\"error\" *ngIf=\"fg.get('phone')?.hasError('phoneInvalid')\"\u003ePlease enter a valid phone number\u003c/div\u003e\n```\n\n* When **valid** → control value = **E.164** string\n* When **invalid/empty** → value = **null**, and validator sets `{ phoneInvalid: true }`\n\n\u003e Need national string instead of E.164? Use `(inputChange)` and store `raw`/`national` yourself, or adapt the emitter to output national.\n\n---\n\n## 🌐 SSR notes\n\n* The library lazy‑imports `intl-tel-input` only in the **browser** (guards with `isPlatformBrowser`).\n* No `window`/`document` usage on the server path.\n\n---\n\n## 🧪 Local development\n\nThis repo is an Angular workspace with a library.\n\n```bash\n# Build the library\nng build ngxsmk-tel-input\n\n# Option A: use it inside a demo app in the same workspace\nng serve demo\n\n# Option B: install locally via tarball in another app\ncd dist/ngxsmk-tel-input \u0026\u0026 npm pack\n# in your other app\nnpm i ../path-to-workspace/dist/ngxsmk-tel-input/ngxsmk-tel-input-\u003cversion\u003e.tgz\n```\n\n\u003e Workspace aliasing via `tsconfig.paths` also works (map `\"ngxsmk-tel-input\": [\"dist/ngxsmk-tel-input\"]`).\n\n---\n\n## 🧯 Troubleshooting\n\n**UI looks unstyled / bullets in dropdown**\nAdd the CSS and assets in `angular.json` (see Install). Restart the dev server.\n\n**Flags don’t show**\nEnsure the assets copy exists under `/assets/intl-tel-input/img` and add the CSS override block above.\n\n**`TS2307: Cannot find module 'ngxsmk-tel-input'`**\nBuild the library first so `dist/ngxsmk-tel-input` exists. If using workspace aliasing, add a `paths` entry to the root `tsconfig.base.json`.\n\n**Peer dependency conflict when installing**\nThe lib peers are `@angular/* \u003e=17 \u003c20`. Upgrade your app or install a compatible version.\n\n**Vite/Angular “Failed to resolve import …”**\nClear `.angular/cache`, rebuild the lib, and restart `ng serve`.\n\n---\n\n## 📃 License\n\n[MIT](./LICENSE)\n\n## 🙌 Credits\n\n* UI powered by [`intl-tel-input`](https://github.com/jackocnr/intl-tel-input)\n* Parsing \u0026 validation by [`libphonenumber-js`](https://github.com/catamphetamine/libphonenumber-js)\n\nLast updated: 2025-08-19\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoozuuu%2Fngxsmk-tel-input","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftoozuuu%2Fngxsmk-tel-input","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoozuuu%2Fngxsmk-tel-input/lists"}