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 (1)

Collapse
 
onlineproxy profile image
OnlineProxy

If you’re cookin’ up Angular 17+ apps and need slick support for international phone inputs, ngxsmk-tel-input is an absolute gem. It’s got native E.164 formatting baked in, plays nice with SSR, and fully supports RTL/i18n-all without dragging in jQuery. Compared to something like ngx-intl-tel-input, this one’s way lighter, tree-shakable, and already vibin’ with standalone components and Angular 19. Plus, it snaps right into Reactive Forms like it was born for it. Honestly, if you’re building modern Angular stuff, this one’s a no-brainer.