npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

kiltel

v3.0.1

Published

Universal international phone input with flag icons and country code sync.

Readme

Kiltel

Kiltel is a lightweight country picker and phone-number formatter. It has no browser-side phone validator: the browser produces a consistent E.164 value and the server decides whether to accept it.

This avoids the old intl-tel-input validation failure that incorrectly rejected some valid India and Jamaica entries.

How number normalization works

Kiltel synchronizes the following values after every edit (include the optional country_iso hidden input when you need the ISO country in your database):

| Field | Stored value | Jamaica example | |---|---|---| | Main phone input | E.164-style full number | +18767425111 | | country_code | Selected dialing prefix | +1876 | | contact | National subscriber digits only | 7425111 | | country_iso | Selected ISO 3166-1 alpha-2 country | JM |

The country prefix is already visible in the main field. Enter only the digits that are not already shown:

  • India: with +91 selected, type 9876543210, which becomes +919876543210.
  • Jamaica: with +1 876 selected, type 7425111, which becomes +18767425111. Jamaica is JM; it shares the North American numbering plan but is not the United States.

Pasting an international number such as +18767425111 also switches the picker to Jamaica automatically. Do not add a leading 0 for an Indian mobile number or repeat a prefix Kiltel has already supplied.

CDN / plain HTML

Add the stylesheet and script:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/kiltel@3/kiltel.min.css">
<script defer src="https://cdn.jsdelivr.net/npm/kiltel@3/kiltel.min.js"></script>

Use this structure for each phone field. The hidden values must be inside the same .kiltel-phone-wrap.

<div class="kiltel-phone-wrap">
  <input
    type="tel"
    class="form-control"
    name="phone"
    data-kilvish-tel
    data-kiltel-init="JM"
    placeholder="Enter the remaining phone digits"
    required
  >
  <input type="hidden" name="country_code">
  <input type="hidden" name="contact">
  <input type="hidden" name="country_iso">
</div>

Kiltel initializes on page load. For markup added later, call window.kiltelInit() after it is inserted.

The CDN build also exposes window.kiltel.normalizePhone(value, country). It returns { country, countryCode, nationalNumber, e164, isPlausible }.

Next.js / React

Kiltel manipulates the DOM, so initialize it only from a client component.

Install and add CSS

npm i kiltel

Import the CSS once, for example in app/layout.js:

import 'kiltel/kiltel-next.css';

App Router client component

'use client';

import { useKiltel } from 'kiltel/kiltel-react';

export default function PhoneField() {
  useKiltel();

  return (
    <div className="kiltel-phone-wrap">
      <input
        type="tel"
        className="form-control"
        name="phone"
        data-kilvish-tel
        data-kiltel-init="IN"
        placeholder="Enter the remaining phone digits"
        required
      />
      <input type="hidden" name="country_code" />
      <input type="hidden" name="contact" />
      <input type="hidden" name="country_iso" />
    </div>
  );
}

Pages Router or scoped manual initialization

import { useEffect, useRef } from 'react';
import kiltel from 'kiltel/kiltel-next';
import 'kiltel/kiltel-next.css';

export default function PhoneField() {
  const wrapRef = useRef(null);

  useEffect(() => {
    kiltel.init({ scope: wrapRef.current });
    return () => kiltel.destroy({ scope: wrapRef.current });
  }, []);

  return (
    <div className="kiltel-phone-wrap" ref={wrapRef}>
      <input type="tel" className="form-control" name="phone" data-kilvish-tel data-kiltel-init="JM" />
      <input type="hidden" name="country_code" />
      <input type="hidden" name="contact" />
      <input type="hidden" name="country_iso" />
    </div>
  );
}

Validate on the server

Do not trust hidden form fields and do not add data-kiltel-validation; that legacy attribute is no longer used. Normalize the submitted main input on the server, then persist the normalized values.

kiltel/kiltel-next can safely be imported by a Next.js route handler because normalizePhone does not access the DOM:

import kiltel from 'kiltel/kiltel-next';

export async function POST(request) {
  const form = await request.formData();
  const phone = kiltel.normalizePhone(
    form.get('phone'),
    form.get('country_iso')
  );

  if (!phone?.isPlausible) {
    return Response.json({ error: 'Enter a complete phone number.' }, { status: 400 });
  }

  // Persist these values, not the client-supplied hidden fields.
  await saveUser({
    phoneE164: phone.e164,
    phoneCountry: phone.country,
    phoneCountryCode: phone.countryCode,
    phoneNationalNumber: phone.nationalNumber
  });

  return Response.json({ ok: true });
}

isPlausible verifies the normalized E.164 shape and length. If your product needs country-specific numbering-plan checks, perform them in that same server route with a maintained server-side telephone library or verification service. No format check can prove that the number is assigned; use SMS or voice verification for that.

Attributes

| Attribute | Purpose | |---|---| | data-kilvish-tel | Enables Kiltel on the input. | | data-kiltel-init | Initial ISO country or dialing prefix, for example IN, JM, or +1876. | | data-kilvish-only | Comma-separated ISO country allow-list, such as IN,JM,US. | | data-kilvish-exclude | Comma-separated ISO country block-list. | | data-kilvish-preferred | Comma-separated ISO countries pinned at the top of the list. |

License

MIT