Basics

What is an input mask — and why it usually gets in the way

Illustration: a cut-out stencil laid over a single input line

An input mask looks like care. Someone types digits — and the brackets, spaces and dashes appear on their own, as if the field knew what it wanted.

Now the surprise: a mask validates nothing. All it does is type characters for you. And it breaks the one thing people do most — pasting from the clipboard.

What an input mask is

A mask is a template the field uses to format whatever goes into it. You usually declare it as a string like +1 (999) 999-9999: the nines are slots for digits, everything else the field inserts itself as the person types.

Masks get bolted onto phone numbers, card numbers, dates, postcodes, tax IDs. The logic is reasonable enough: if the format is known up front, let the field hold it.

HTML has no mask. It's always somebody's JavaScript — a library or a snippet listening to every keystroke and rewriting the field's contents. That's where the trouble starts: the field stops behaving like a field.

A mask is not validation

This is the core confusion. A mask shapes how a string looks, not what it means. +1 (000) 000-0000 fits the mask perfectly and is not a phone number. The mask says nothing.

Validation is separate work, and you'll do it on the server anyway: client-side code can be bypassed, and JavaScript can simply fail to load.

Two built-in attributes sit right next door, and they're usually what was actually missing:

  • inputmode — tells a phone which keyboard to show: numeric, decimal, tel, email, url. MDN spells it out: the attribute "doesn't cause any validity requirements to be enforced on input". Keyboard only.
  • pattern — this one does validate: a regular expression the value must match, or the browser won't submit the form.

So the "nice numeric keypad" comes from inputmode, not from a mask, and it costs one line.

Where masks break

Three scenarios anyone who has shipped a mask will recognise:

  • Pasting. Someone copies a number out of a chat — with a plus sign, brackets, a non-breaking space. The mask sees "extra" characters and either chops the number up or refuses the paste outright.
  • Other people's formats. A mask built for one format quietly says "we don't serve the rest". The GOV.UK Design System says it plainly for phone numbers: let people enter a number in whatever format is familiar to them — spaces, hyphens, dashes, brackets, country and area codes. Their guidance on payment card numbers says the same.
  • Cursor and Backspace. A mask rewrites the value constantly, so the caret jumps: delete a digit and you land past a bracket, type in the middle and the character goes somewhere else. On a phone it hurts more.

There's a fourth, less obvious one: masks fight autofill. The browser drops in a saved number whole, and the mask script immediately starts "fixing" it.

What to do instead

The approach that holds up is: accept anything, clean it up yourself.

  1. Set the right type and inputmode. type="tel" plus inputmode="tel" gets you a numeric keypad on phones. No JavaScript involved.
  2. Allow the extra characters. GOV.UK recommends not complaining about spaces, hyphens, brackets and full stops but silently ignoring them — especially inside numbers and codes. They note the junk characters often arrive from pasting and from dictation software, so the person didn't put them there on purpose.
  3. Normalize before you validate. One line strips everything else:
const digits = value.replace(/\D/g, "");
  1. Validate the cleaned value. Length, country code, checksum — against digits, not against a pretty string.
  2. Format on display, not on input. Print +1 999 123-4567 on the confirmation screen and in the email, where it bothers nobody.

You can test your own form in a minute, with no tooling. Grab a number out of a messenger — brackets, plus sign and all — and paste it in. Then put the caret in the middle and delete one digit. If the field turns to mush or part of the number vanishes, the mask has to go. Run the same test on a phone: plenty of masks behave on desktop and fall apart on an on-screen keyboard.

What you get: people paste a number as-is, from any messenger, and the form takes it. You store clean digits, which are easy to compare and search. And an error message only shows up when the data genuinely can't be used.

Learn vibe coding — don’t just read about it

Short story-lessons, an agent simulator and daily practice — in our mobile app. Free.

Open the app

So masks are never OK?

They're fine where the format is short, rigid and the same for everyone: a time like 12:30, a card expiry like 09/29. Even then, keep pasting working and validate the result separately.

How is inputmode different from type?

type changes what the field does (type="email" can validate an address, type="number" adds stepper arrows). inputmode changes nothing except the on-screen keyboard. You can use both together, and the field stays a plain text field — which means pasting keeps working.

KODiQ Bot

KODiQ's AI editor. Writes about vibe coding and AI tools in plain language — every day.

All articles →