D
P
0

JavaScript

HTML5 `pattern` Validation Breaks in Chrome with a `SyntaxError`? The `v` Flag Requires Escaping `(`

July 22, 2026·4 min read
HTML5 `pattern` Validation Breaks in Chrome with a `SyntaxError`? The `v` Flag Requires Escaping `(`

On a client site, a booking platform with an owner registration form, one field was a phone number. I had added light validation through the HTML5 pattern attribute so people could not type letters into a phone field. It worked in Firefox. It worked locally. But in Chrome the phone field behaved as if it had no validation at all: anything I typed passed, and submit never blocked obviously wrong input.

What made me suspicious was that this did not look like a regex that was merely too loose. If pattern had parsed but been permissive, that would still be explainable behavior. This was different: the browser seemed to throw the whole pattern attribute away. And that is exactly what was happening. When a pattern cannot compile into a valid regex, the HTML spec says the constraint is ignored, so the field is treated as always valid. Validation silently broken, no error visible in the UI.

Dead ends I tried

My first reflex was that I had written the regex wrong. My original pattern was roughly this:

<input id="register-phone" pattern="[0-9 +().-]*">

I figured the - in the middle of the character class was being read as a range. So I moved it around and tried a few variants:

<!-- still failing in Chrome -->
<input pattern="[-0-9 +().]">
<input pattern="[0-9 +().\-]*">

Still failing. Moving - to the edge of the class is genuinely the right habit to avoid an accidental range, but in Chrome it made no difference. The field stayed unvalidated. At that point I realized I was just guessing, and guessing at regex is a waste of time. I needed to see the real error.

Finding the actual error

Since pattern is a regex under the hood, I compiled the pattern string directly in the console the way a modern browser does it. Chrome now validates pattern with the v flag, so I mirrored that:

new RegExp(document.querySelector('#register-phone').pattern, 'v');
// Uncaught SyntaxError: Invalid regular expression

There it finally spoke up: a SyntaxError. Not a loose regex, a regex that could not compile at all. That un-compilable constraint was what got silently discarded, which is why the field accepted anything.

Root cause: the v flag

Here is the surprising part. Chrome now compiles the HTML5 pattern with the v flag (unicodeSets mode) from ECMAScript 2024, not the old plain regex mode. The v flag introduces much stricter character-class rules. One of them: a specific set of punctuation characters is treated as reserved "double punctuators" inside a character class, and ( is one that must be escaped. In the old mode, ( inside a character class was just a literal character and caused no trouble. In v mode, an unescaped ( inside a character class is a syntax error.

So all my guessing about - was aimed at the wrong target. What Chrome rejected was not the minus sign, it was the parentheses ( and ) I had left bare inside the class. Firefox and older Chrome builds still use the old regex parser, which is why the same pattern passed there. The moment Chrome switched to v, a character class that used to be legal became illegal.

The fix

The fix is not to reshuffle character order, it is to escape every special character explicitly so it is valid under v mode:

<input id="register-phone" pattern="[\d\s+\(\)\.\-]*">

\d for digits, \s for whitespace, then \(, \), \., and \- for the escaped parens, dot, and minus. I verified it the same way that told me the cause in the first place:

new RegExp(document.querySelector('#register-phone').pattern, 'v');
// throws nothing

No SyntaxError. The field validated again: it accepted reasonable local phone formats and rejected input like abc. In code the change is only a few backslashes, but without knowing about the v flag those backslashes look redundant and are easy to dismiss as unnecessary.

Takeaways

  • If an HTML5 pattern is being "ignored" in one browser, do not assume the regex is loose; it may be failing to compile and getting silently dropped.
  • Reproduce with new RegExp(el.pattern, 'v') in the console to force the real SyntaxError instead of guessing.
  • Chrome validates pattern with the ECMAScript 2024 v flag; v mode character classes are far stricter than the old mode.
  • In v mode, ( and a set of other punctuation are reserved characters inside a character class and must be escaped.
  • Explicit escaping is portable: [\d\s+\(\)\.\-]* is valid under both the old parser and v, so it is safe across browsers.
  • Cross-browser differences on pattern are usually about the regex parser version, not a bug in your form logic.