Skip to content

Phone field as custom elements

@telixon/web-components has three parts. <telixon-phone-field> turns the <input> inside it into a phone field the form submits and validates like a native field. The user sees a formatted number while the form submits it in E.164. The input stays in the page, where your labels, styles, and autofill apply to it. <telixon-region-picker> adds the flag and a searchable list of regions. <telixon-flag> shows the flag of a region. All three are custom elements built on @telixon/web-sdk. They run in every current browser and inside the markup of any framework.

Terminal window
npm install @telixon/web-components

The package depends on @telixon/core and @telixon/web-sdk and re-exports both. One import covers every element, function, and type.

@telixon/web-components/flags/flags.css paints the flags, on the page and inside the picker. Import it once, from the page’s stylesheet or from the entry module of a bundled application:

@import '@telixon/web-components/flags/flags.css';

One call defines the three elements. On a server-rendered page it belongs in the client entry, as defineTelixonElements describes:

import { defineTelixonElements } from '@telixon/web-components';
defineTelixonElements();

A phone field with a region picker inside a form. Type a number, pick a region, and save:

Value: null

Submitted: none

The demo runs the three files below. The markup is a form with the field around the input. The stylesheet lays the field out. The script defines the elements and reads the value. The example is a Vite project, which resolves the package from the module script. A page without a bundler loads the package through an import map, as the frameworks guide shows.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Phone field</title>
<link rel="stylesheet" href="/src/static/styles.css" />
<script type="module" src="/src/static/main.ts"></script>
</head>
<body>
<form id="contact">
<label for="phone-input">Phone</label>
<telixon-phone-field name="phone" default-region="US" calling-code-in-input="false" auto-placeholder required>
<telixon-region-picker></telixon-region-picker>
<input id="phone-input" type="tel" autocomplete="tel" />
</telixon-phone-field>
<button>Save</button>
<p>Value: <output id="value">null</output></p>
<p>Submitted: <output id="submitted">none</output></p>
</form>
</body>
</html>

The same field runs on StackBlitz, on its own, in React 19, or in Vue 3.

At first the picker shows the United States flag with +1 and the field shows the placeholder 201-555-0123. After typing 4155550132 the field shows 415-555-0132 while the value reads +14155550132. Save submits phone=+14155550132. A partial number keeps the value at null and blocks the submission with This number is too short. anchored at the input. Clear the field, pick the United Kingdom, and type 2071838750. The field then shows 20 7183 8750 with the value +442071838750.

The field loads the engine the first time it connects, which the engine-loading state marks. Until then the input is a plain input. An application that wants the engine earlier calls ensureEngineReady, which the package re-exports, before the field appears.

The elements need form-associated custom elements, custom states, and the Popover API. Custom states and the popover set the floor:

Browser Version
Chrome 125
Edge 125
Firefox 126
Safari 17.4
iOS Safari 18.3