DEV Community

Sachin Dilshan
Sachin Dilshan

Posted on • Edited on

ngxsmk-tel-input — International Phone Input for Angular (E.164, i18n, RTL)

I’ve shipped a small, focused UI component for modern Angular apps: an international telephone input with country flags, dropdown, and real validation/formatting.

It wraps the excellent intl-tel-input for UI and libphonenumber-js for validation/parsing, and exposes a clean Angular API that works with Reactive & Template-driven Forms (CVA). It emits E.164 numbers by default (e.g. +14155550123), and is SSR-safe.

TL;DR

✅ UI via intl-tel-input, rules via libphonenumber-js

✅ Emits clean E.164 values

✅ Works with Reactive & Template forms (ControlValueAccessor)

✅ Angular 17–19, standalone, SSR-friendly

✅ Options: separateDialCode, nationalMode, preferredCountries, attach dropdown to

, sizes, variants, clear button, autofocus, select-on-focus

🌍 Localization & RTL: customize labels, country names, and direction

🔒 Optional digits-only input mode (with single leading +)

NPM: https://www.npmjs.com/package/ngxsmk-tel-input
GitHub: https://github.com/toozuuu/ngxsmk-tel-input

Install

npm i ngxsmk-tel-input intl-tel-input libphonenumber-js

Add styles & flag assets in your app (not the library). Update angular.json:


{
  "projects": {
    "your-app": {
      "architect": {
        "build": {
          "options": {
            "styles": [
              "node_modules/intl-tel-input/build/css/intlTelInput.css"
            ],
            "assets": [
              { "glob": "**/*", "input": "node_modules/intl-tel-input/build/img", "output": "assets/intl-tel-input/img" }
            ]
          }
        }
      }
    }
  }
}

Enter fullscreen mode Exit fullscreen mode

Optional (helps some setups resolve flags):

/* global styles */

.iti__flag { background-image: url("/assets/intl-tel-input/img/flags.png"); }
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
  .iti__flag { background-image: url("/assets/intl-tel-input/img/flags@2x.png"); }
}
Enter fullscreen mode Exit fullscreen mode

Restart your dev server after editing angular.json.

Quick Start (Reactive Forms)

// app.component.ts
import { Component, inject } from '@angular/core';
import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';
import { JsonPipe } from '@angular/common';
import { NgxsmkTelInputComponent } from 'ngxsmk-tel-input';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [ReactiveFormsModule, NgxsmkTelInputComponent, JsonPipe],
  template: `
    <form [formGroup]="fg" style="max-width:420px;display:grid;gap:12px">
      <ngxsmk-tel-input
        formControlName="phone"
        label="Phone"
        hint="Include area code"
        [initialCountry]="'US'"
        [preferredCountries]="['US','GB','AU']">
      </ngxsmk-tel-input>

      <pre>Value: {{ fg.value | json }}</pre>
    </form>
  `,
})
export class AppComponent {
  private readonly fb = inject(FormBuilder);
  fg = this.fb.group({ phone: ['', Validators.required] });
}
Enter fullscreen mode Exit fullscreen mode

Value semantics: The control emits E.164 (e.g., +14155550123) when valid, or null when empty/invalid.

Localization & RTL (i18n)

Customize dropdown/search labels and country names. RTL is as easy as dir="rtl".

import { Component, inject } from '@angular/core';
import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';
import { NgxsmkTelInputComponent, IntlTelI18n, CountryMap } from 'ngxsmk-tel-input';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [ReactiveFormsModule, NgxsmkTelInputComponent],
  template: `
    <form [formGroup]="fg" style="max-width:420px;display:grid;gap:12px">
      <ngxsmk-tel-input
        formControlName="phone"
        label="전화번호"
        hint="지역 번호를 포함하세요"
        placeholder="전화번호 입력"
        dir="ltr"
        [initialCountry]="'KR'"
        [preferredCountries]="['KR','US','JP']"
        [i18n]="koLabels"
        [localizedCountries]="koCountries">
      </ngxsmk-tel-input>

      <pre>Value: {{ fg.value | json }}</pre>
    </form>
  `
})
export class AppComponent {
  private fb = inject(FormBuilder);
  fg = this.fb.group({ phone: ['', Validators.required] });

  // Korean UI labels (dropdown/search/ARIA)
  koLabels: IntlTelI18n = {
    selectedCountryAriaLabel: '선택한 국가',
    countryListAriaLabel: '국가 목록',
    searchPlaceholder: '국가 검색',
    zeroSearchResults: '결과 없음',
    noCountrySelected: '선택된 국가 없음'
  };

  // Korean country names (override what you need)
  koCountries: CountryMap = {
    KR: '대한민국',
    US: '미국',
    JP: '일본',
    CN: '중국',
    GB: '영국',
    DE: '독일',
    FR: '프랑스',
    AU: '호주',
    CA: '캐나다',
    IN: '인도'
  };
}

Enter fullscreen mode Exit fullscreen mode

Prefer Korean? Swap labels/countries to ko-KR equivalents and set dir="ltr".

Optional: Digits-Only Input

You can forbid non-numeric characters (optionally allowing a single leading +):

<ngxsmk-tel-input
  formControlName="phone"
  [digitsOnly]="true"
  [allowLeadingPlus]="true">
</ngxsmk-tel-input>
Enter fullscreen mode Exit fullscreen mode

This filters typing/paste (and keeps programmatic updates clean), while validation still uses libphonenumber-js.

Theming (CSS Variables)

<ngxsmk-tel-input style="
  --tel-border:#cbd5e1;
  --tel-ring:#22c55e;
  --tel-radius:14px;
  --tel-dd-item-hover: rgba(34,197,94,.12);
"></ngxsmk-tel-input>
Enter fullscreen mode Exit fullscreen mode

Dark mode? Wrap a parent in .dark — tokens adapt automatically.

SSR Notes

The component lazy-loads intl-tel-input only in the browser (guarded with isPlatformBrowser), so no window access on the server.

Troubleshooting

  • Unstyled dropdown / missing flags → ensure CSS & assets are added in angular.json, then restart dev server.
  • Flags don’t show → add the CSS override block shown above to point to /assets/intl-tel-input/img.
  • Peer dependency conflict → the library peers target @angular/* >=17 <20.
  • Can’t import the package in a workspace → build the lib (ng build ngxsmk-tel-input) or use a tarball install.

Roadmap & Contributions

  • Accessibility polish & docs samples
  • More presets & examples (StackBlitz)
  • Community requests!

PRs, issues, and ideas are super welcome 🙌

NPM: https://www.npmjs.com/package/ngxsmk-tel-input
GitHub: https://github.com/toozuuu/ngxsmk-tel-input

If you try it, I’d love your feedback. Happy building! 💚

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.