D
P
0

JavaScript

Validasi `pattern` HTML5 Rusak di Chrome karena `SyntaxError`? Flag `v` Mewajibkan `(` Di-escape

22 Juli 2026·3 menit baca
Validasi `pattern` HTML5 Rusak di Chrome karena `SyntaxError`? Flag `v` Mewajibkan `(` Di-escape

Di sebuah situs klien, sebuah platform booking, ada form registrasi pemilik properti. Salah satu field-nya nomor telepon, dan saya pasang validasi ringan lewat atribut pattern HTML5 supaya orang tidak mengetik huruf ngawur di kolom telepon. Di Firefox jalan. Di lokal jalan. Tapi di Chrome, field telepon itu seperti tidak punya validasi sama sekali: apa pun yang saya ketik lolos, dan tombol submit tidak pernah menahan input yang jelas-jelas salah.

Yang bikin curiga, ini bukan soal regex-nya kurang ketat. Kalau pattern di-parse tapi terlalu longgar, itu masih perilaku yang bisa dijelaskan. Ini beda: seolah-olah browser membuang atribut pattern itu bulat-bulat. Dan memang begitulah yang terjadi. Ketika sebuah pattern tidak bisa di-compile jadi regex yang valid, spec HTML bilang constraint-nya diabaikan, jadi field-nya dianggap selalu valid. Validasi rusak, tanpa pesan error apa pun yang kelihatan di UI.

Jalan buntu yang saya coba

Refleks pertama saya: pasti regex-nya salah tulis. Pattern awal saya kira-kira begini:

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

Saya pikir mungkin tanda - di tengah character class ditafsirkan sebagai range. Jadi saya pindahkan ke depan dan coba beberapa varian lain:

<!-- masih gagal di Chrome -->
<input pattern="[-0-9 +().]">
<input pattern="[0-9 +().\-]*">

Semua masih gagal. Memindahkan - ke ujung memang praktik yang benar untuk menghindari range yang tidak disengaja, tapi di Chrome tidak ada bedanya. Field-nya tetap seperti tidak tervalidasi. Di titik ini saya sadar saya cuma menebak-nebak, dan menebak regex itu buang waktu. Saya perlu melihat error yang sebenarnya.

Menemukan error yang sesungguhnya

Karena pattern di bawah kap adalah regex, saya coba compile string pattern itu langsung di console persis seperti browser modern melakukannya. Chrome sekarang memvalidasi pattern dengan flag v, jadi saya tiru:

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

Di situ akhirnya keluar suaranya: SyntaxError. Bukan regex yang longgar, tapi regex yang sama sekali tidak bisa di-compile. Constraint yang tidak bisa di-compile itulah yang diam-diam dibuang, dan itu sebabnya field-nya lolos apa saja.

Akar masalahnya: flag v

Ini bagian yang mengejutkan. Chrome kini meng-compile pattern HTML5 dengan flag v (mode unicodeSets) dari ECMAScript 2024, bukan lagi mode regex biasa. Flag v memperkenalkan aturan character class yang jauh lebih ketat. Salah satu aturannya: sederet karakter tanda baca tertentu diperlakukan sebagai "double punctuator" yang direservasi di dalam character class, dan ( termasuk yang harus di-escape. Di mode lama, ( di dalam sebuah character class diperlakukan sebagai karakter literal biasa dan tidak masalah. Di mode v, ( yang tidak di-escape di dalam character class adalah syntax error.

Jadi semua tebakan saya soal - itu salah sasaran. Yang bikin Chrome menolak bukan tanda minus, tapi tanda kurung ( dan ) yang saya biarkan telanjang di dalam class. Firefox dan build Chrome yang lebih lama masih memakai parser regex yang lama, makanya pattern yang sama lolos di sana. Begitu Chrome pindah ke v, character class yang dulu sah jadi ilegal.

Perbaikannya

Solusinya bukan mengakali urutan karakter, tapi meng-escape setiap karakter khusus secara eksplisit sehingga valid di mode v:

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

\d untuk digit, \s untuk spasi, lalu \(, \), \., dan \- untuk kurung, titik, dan minus yang di-escape semua. Saya verifikasi langsung dengan cara yang sama yang tadi memberi tahu saya penyebabnya:

new RegExp(document.querySelector('#register-phone').pattern, 'v');
// tidak melempar apa pun

Tidak ada SyntaxError. Field-nya kembali memvalidasi: menerima format nomor telepon lokal yang wajar dan menolak input seperti abc. Dari sisi kode, perubahannya cuma beberapa backslash, tapi tanpa tahu soal flag v, backslash itu terlihat berlebihan dan gampang dianggap tidak perlu.

Pelajaran

  • Kalau pattern HTML5 seakan "diabaikan" di satu browser, jangan asumsikan regex-nya longgar; bisa jadi regex-nya gagal di-compile dan constraint-nya dibuang diam-diam.
  • Reproduksi dengan new RegExp(el.pattern, 'v') di console untuk memaksa munculnya SyntaxError yang sebenarnya, alih-alih menebak.
  • Chrome memvalidasi pattern dengan flag v ECMAScript 2024; character class mode v jauh lebih ketat dari mode lama.
  • Di mode v, ( dan sederet tanda baca lain adalah karakter reservasi di dalam character class dan wajib di-escape.
  • Escape eksplisit itu portable: [\d\s+\(\)\.\-]* valid di parser lama maupun v, jadi aman lintas browser.
  • Beda perilaku antar-browser pada pattern biasanya soal versi parser regex, bukan bug di logika form kamu.