Formulir HTML memiliki sistem validasi bawaan: atribut seperti required, type="email", dan minlength membuat browser menilai sendiri apakah isian memenuhi syarat. CSS dapat membaca hasil penilaian tersebut lewat pseudo-class :valid dan :invalid — tanpa JavaScript. Namun ada jebakan pengalaman pengguna yang wajib dipahami sejak awal: :invalid aktif sejak halaman dimuat, sehingga input wajib yang belum diisi apa pun langsung tampil merah sebelum pengguna sempat mengetik. Pada Chapter ini kita menata kedua pseudo-class tersebut, lalu memperkenalkan :user-valid dan :user-invalid yang menunggu pengguna berinteraksi terlebih dahulu.

:valid dan :invalid Aktif Sejak Awal #

Pseudo-class ini mengikuti status validasi elemen secara langsung:

css
.input {
  font: inherit;
  padding: 8px 12px;
  border: 2px solid rgb(203, 213, 225);
  border-radius: 8px;
}

.input:invalid { border-color: rgb(220, 38, 38); }
.input:valid   { border-color: rgb(22, 163, 74); }

Mari kita telaah perilakunya:

  1. Baris 1–6 (.input): gaya dasar input dengan border netral — seluruh status nantinya hanya mengganti warna border, bukan menambah properti baru.
  2. Baris 8 (.input:invalid): bila elemen gagal validasi, border berubah merah. Untuk <input required> yang kosong, kondisi ini telah terpenuhi pada detik halaman dibuka — isi kosong gagal syarat required.
  3. Baris 9 (.input:valid): bila isian memenuhi semua syarat — misalnya type="email" berisi [email protected] — border berubah hijau.

Hasil di Browser:

text
Input email wajib yang kosong: border merah rgb(220, 38, 38)
sejak halaman dimuat — :invalid aktif tanpa interaksi.
Input email berisi [email protected]: border hijau rgb(22, 163, 74).
Input yang dinonaktifkan: latar rgb(241, 245, 249) dan teks
rgb(148, 163, 184).

Ketiga nilai itu diprobe otomatis pada demo — termasuk border merah pada input yang belum pernah disentuh, bukti nyata perilaku “merah sejak awal” di atas.

:user-valid dan :user-invalid yang Menunggu Interaksi #

:user-invalid dan pasangannya :user-valid memperbaiki masalah tersebut: keduanya baru cocok setelah pengguna berinteraksi dengan kontrol — mengetik lalu membuatnya tidak sah, atau mengosongkan kembali field yang telah diisi. Fitur ini merupakan Baseline sejak 2024. Strategi yang nyaman dipakai: biarkan :invalid untuk sinyal halus (misalnya warna teks hint), dan serahkan sinyal kuat seperti border merah mencolok kepada :user-invalid:

css
.input:user-invalid { border-color: rgb(147, 51, 234); }

Pada demo, aturan ungu ini diletakkan setelah aturan merah — bila keduanya cocok, ungu menang karena urutan source. Namun probe menunjukkan border tetap merah: pada keadaan awal tanpa interaksi, :user-invalid belum cocok, sehingga aturan ungu tidak berlaku. Inilah perbedaan keduanya dalam satu gambar: :invalid menilai data, :user-invalid menilai data dan pengalaman pengguna.

:required, :optional, dan :disabled #

Tiga pseudo-class lain melengkapi kotak peralatan validasi. :required dan :optional membedakan field wajib dari bebas — pasangan yang tepat untuk menambah tanda bintang atau label “opsional” tanpa class tambahan. Sementara itu, :disabled menata elemen dengan atribut disabled: kontrol tersebut tidak dapat diedit, tidak ikut dikirim saat form disubmit, dan dilewati navigasi Tab. Gaya khasnya adalah latar dan teks yang redup — bukan sekadar opacity, karena teks redup eksplisit lebih dapat diprediksi di seluruh browser:

css
.input:disabled {
  background-color: rgb(241, 245, 249);
  color: rgb(148, 163, 184);
}

Dengan keenam pseudo-class di atas — :valid, :invalid, :user-valid, :user-invalid, :required, dan :disabled — status setiap kontrol dapat ditata murni lewat CSS, dan JavaScript cukup menangani pesan galat yang lebih kompleks.