HTML form doğrulaması, tarayıcının bir formu göndermeden önce alanların kurallara uyup uymadığını kendi başına denetlemesidir. Bir alanı zorunlu yapmak için required, uzunluğu sınırlamak için minlength ve maxlength, biçim dayatmak için pattern, sayı ve tarih aralığı için min, max ve step özniteliklerini eklemeniz yeterlidir. Kural bozulursa tarayıcı gönderimi durdurur ve ilk geçersiz alanda bir hata mesajı gösterir. Bunun için tek satır JavaScript yazmanız gerekmez.
MDN bu mekanizmaya "constraint validation" (kısıt doğrulaması) adını verir. Bu yazıda her özniteliğin hangi <input> türlerinde çalıştığını, hangi hata türünü ürettiğini, boş alanların neden çoğu zaman geçerli sayıldığını, novalidate ile doğrulamanın nasıl kapatıldığını ve en sık yapılan hataları göreceksiniz. Form etiketinin genel yapısı için form etiketi rehberine, tüm seri için HTML öğrenme rehberi sayfasına bakabilirsiniz.
Kısıt doğrulaması iki kaynaktan gelir
Tarayıcının uyguladığı kurallar iki yerden doğar. Birincisi alanın type değeridir: type="email" seçtiğinizde değerin sözdizimi açısından geçerli bir e-posta adresi olması, type="url" seçtiğinizde mutlak bir URL olması kendiliğinden beklenir. Bu kurala uymayan değer typeMismatch hatası üretir. İkincisi doğrulamayla ilgili özniteliklerdir: required, pattern, minlength, maxlength, min, max ve step. Bunlar JavaScript gerektirmeden kural tanımlamanızı sağlar.
MDN şunu da vurgular: çoğu input türünün kendine özgü bir kısıtı yoktur. Bazı türler doğrulamanın dışında tutulur, bazılarında ise tarayıcı yanlış değeri bir temizleme algoritmasıyla geçerli bir varsayılana çevirir. Örneğin range türü hiçbir zaman boş değer taşımaz; bu yüzden required orada anlamsızdır. Türlerin tam listesi için input türleri rehberine bakın.
required: alanı zorunlu yapmak
required bir Boolean özniteliktir; yazılması "doğru", yazılmaması "yanlış" demektir, bu yüzden değer vermeniz gerekmez. MDN'e göre text, search, url, tel, email, password, date, month, week, time, datetime-local, number, checkbox, radio ve file türlerinde, ayrıca <select> ve <textarea> öğelerinde çalışır. Değer boş dizeyse alan valueMissing durumuna düşer ve geçersiz sayılır.
Bazı yerlerde hiçbir etkisi yoktur. range ve color her zaman bir varsayılan değer taşıdığı için zorunluluk anlamsızdır; hidden alanı kullanıcı göremediği için dolduramaz; düğme türlerinde (image dahil) de desteklenmez. Ayrıca readonly bir alan kullanıcı tarafından değiştirilemediği için aynı alana yazılan required yok sayılır.
Gruplarda davranış türüne göre değişir. Aynı name değerini paylaşan radyo düğmelerinden yalnızca birinde required olsa bile gruptan bir seçenek işaretlenmek zorundadır; işaretlenenin özniteliği taşıyan düğme olması gerekmez. MDN, bakımı kolaylaştırmak için özniteliği ya gruptaki her düğmeye ya da hiçbirine yazmanızı önerir. Onay kutularında ise tersine, yalnızca required taşıyan kutu zorunludur. Ayrıntılar checkbox ve radio yazısında.
<form action="/kayit" method="post">
<label for="ad">Ad soyad (zorunlu)</label>
<input id="ad" name="ad" type="text" required />
<fieldset>
<legend>İletişim tercihi (zorunlu)</legend>
<!-- grubun tamamına required yazmak bakımı kolaylaştırır -->
<label><input type="radio" name="iletisim" value="eposta" required /> E-posta</label>
<label><input type="radio" name="iletisim" value="telefon" required /> Telefon</label>
</fieldset>
<button type="submit">Gönder</button>
</form>minlength ve maxlength: karakter sayısı
minlength en az, maxlength en çok kaç karakter girilebileceğini belirler. Değer 0 veya daha büyük bir tam sayı olmalıdır ve minlength, maxlength değerinden büyük olamaz; büyük olursa iki koşul aynı anda sağlanamayacağı için alan hiçbir zaman geçerli olmaz. Uzunluk UTF-16 kod birimiyle ölçülür; bu çoğu zaman karakter sayısına eşittir ama MDN'in vurguladığı gibi her zaman değil.
İki önemli ayrıntı vardır. Birincisi, minlength alanı zorunlu yapmaz. Alan required değilse boş bırakılıp gönderilebilir; kısa ama boş olmayan bir değer ise tooShort hatası verir. İkincisi, bu iki kısıt yalnızca kullanıcının girdiği değerde denetlenir. Değeri JavaScript ile atarsanız, checkValidity() çağırsanız bile kontrol edilmez. maxlength için tarayıcı genellikle sınırdan fazla yazmanıza zaten izin vermez; yine de uzunluk aşılırsa tooLong doğru olur.
<label for="kadi">Kullanıcı adı (3 ile 20 karakter)</label>
<input id="kadi" name="kadi" type="text" minlength="3" maxlength="20" required />
<label for="not">Kısa not (isteğe bağlı, en az 10 karakter)</label>
<textarea id="not" name="not" minlength="10" maxlength="200"></textarea>İkinci alanda required olmadığı için boş not geçerlidir; "merhaba" yazılırsa yedi karakter olduğu için geçersiz olur. Çok satırlı alanların diğer öznitelikleri textarea yazısında anlatılıyor.
pattern: düzenli ifadeyle biçim dayatmak

pattern, değerin uyması gereken bir JavaScript düzenli ifadesi alır. Yalnızca text, tel, email, url, password ve search türlerinde geçerlidir. Değer boş değilse ve ifadeye uymuyorsa patternMismatch hatası oluşur. Bu davranışın üç kuralını bilmek, hataların çoğunu önler:
- Değerin tamamı eşleşmelidir. Tarayıcı ifadenin başına
^(?:, sonuna)$eklenmiş gibi davranır.[a-z]{4,8}yazdığınızda "abcd1" değeri, içinde dört küçük harf olsa da geçersizdir. - Eğik çizgi yazılmaz. JavaScript'teki
/.../sınırlayıcıları ve bayraklar kullanılmaz. Öznitelik değeri yoksa, boşsa veya geçersiz bir ifadeyse hiçbir kural uygulanmaz. - İfade
vbayrağıyla derlenir. Bu Unicode farkındalığı sağlar ve karakter sınıflarının yorumunu değiştirir. MDN'e göre bir karakter sınıfının içinde]ve\dışında( ) [ { } / - |karakterleri de düz karakter olarak kullanılacaksa ters eğik çizgiyle kaçırılmalıdır. Eski kodda[a-z0-9-_]gibi bir sınıf varsa tireyi kaçırın.
<label for="uye">Üye kodu</label>
<input
id="uye"
name="uye"
type="text"
pattern="[a-z]{4,8}"
title="4 ile 8 arası küçük harf"
aria-describedby="uye-ipucu"
required />
<p id="uye-ipucu">Yalnızca küçük harf, 4 ile 8 karakter.</p>Örnekteki title özniteliği bazı tarayıcılarda hata mesajına eklenir, bazılarında fareyle üzerine gelince ipucu olarak görünür. MDN bu nedenle iki uyarı yapar: kuralı mutlaka görünür bir metinle de yazın, çünkü yalnızca klavye veya dokunmatik ekran kullananlar title ipucunu göremeyebilir; ve title metnini hata cümlesi gibi kurmayın, çünkü hata yokken de görünebilir. Açıklamayı alana bağlamak için kullanılan aria-describedby için erişilebilir ad yazısına bakabilirsiniz.
min, max ve step: aralık ve adım

min ve max kabul edilen en küçük ve en büyük değeri, step ise değerlerin hangi aralıklarla ilerleyeceğini belirler. Bu üçlü number, range ve tarih/saat türlerinde (date, month, week, time, datetime-local) çalışır. Değer min altında kalırsa rangeUnderflow, max üstüne çıkarsa rangeOverflow, adıma oturmazsa stepMismatch oluşur. min veya max geçerli bir sayıya ya da tarihe çevrilemiyorsa o sınır hiç yokmuş gibi davranılır.
Adım hesabının bir başlangıç noktası vardır: min varsa odur, yoksa value, ikisi de yoksa 0. Geçerli değerler bu başlangıçtan tam adım sayısı kadar uzaktaki değerlerdir. MDN'in input sayfasındaki örnek bunu iyi gösterir: min="2" max="10" step="2" olan bir sayı alanında yalnızca 2, 4, 6, 8 ve 10 geçerlidir. 3 yazılırsa stepMismatch, 1 yazılırsa rangeUnderflow, 12 yazılırsa rangeOverflow hatası alınır. step="any" adım denetimini kapatır.
<label for="kisi">Kişi sayısı (2 ile 10 arası, çift sayı)</label>
<input id="kisi" name="kisi" type="number" min="2" max="10" step="2" />
<label for="fiyat">Fiyat (kuruşlu)</label>
<input id="fiyat" name="fiyat" type="number" min="0" step="0.01" />step belirtmediğinizde varsayılan adım number ve range için 1'dir; bu yüzden kuruşlu fiyat girmek isteyen kullanıcı 9,99 yazdığında alan geçersiz olur. Ondalık gerekiyorsa step="0.01" veya step="any" yazın. Sayı ve kaydırıcı alanlarının tüm ayrıntıları number ve range yazısında, tarih türlerindeki adım birimleri (gün, ay, hafta, saniye) ise tarih ve saat alanları yazısında anlatılıyor.
Boş alan ne zaman geçerlidir?
Yeni başlayanları en çok şaşırtan kural budur. MDN'e göre required dışındaki kısıtların hiçbiri boş değer için hata üretmez. pattern, minlength, min veya type="email" taşıyan ama boş bırakılan bir alan geçerlidir ve form gönderilir. Bir alanın hem doldurulmasını hem de belirli bir biçimde olmasını istiyorsanız required ile biçim özniteliğini birlikte kullanmalısınız.
Hata türleri: ValidityState özeti
Her form denetiminin validity özelliği bir ValidityState nesnesi döndürür. Bu nesnedeki Boolean alanlar, değerin neden geçersiz olduğunu tek tek söyler. Aşağıdaki tablo hangi özniteliğin hangi alanı tetiklediğini özetler:
| Öznitelik veya durum | ValidityState alanı | Ne zaman doğru olur |
|---|---|---|
| required | valueMissing | Değer boş, radyo grubunda veya onay kutusunda seçim yok |
| type (email, url) | typeMismatch | Değer türün beklediği sözdizimine uymuyor |
| pattern | patternMismatch | Boş olmayan değer ifadenin tamamına uymuyor |
| minlength | tooShort | Kullanıcının girdiği değer çok kısa |
| maxlength | tooLong | Kullanıcının girdiği değer çok uzun |
| min | rangeUnderflow | Değer alt sınırın altında |
| max | rangeOverflow | Değer üst sınırın üstünde |
| step | stepMismatch | Değer adım başlangıcından tam adım uzaklığında değil |
| Tarayıcının çeviremediği giriş | badInput | Örneğin sayı alanına sayı olmayan bir şey girilmiş |
| setCustomValidity() | customError | Betikle boş olmayan bir hata mesajı atanmış |
Tablodaki koşulların hiçbiri doğru değilse valid alanı doğru olur ve form gönderilebilir.
Doğrulama ne zaman çalışır?
MDN iki tür doğrulama ayırır. Statik doğrulama, bir öğede ya da formun tamamında checkValidity() çağrıldığında olur: sonuç true veya false olarak döner, geçersizse öğede bir invalid olayı tetiklenir ama kullanıcıya bir şey gösterilmez. Etkileşimli doğrulama ise reportValidity() çağrıldığında veya form gönderilmeye çalışıldığında olur; tarayıcı bu durumda sorunu kullanıcıya bildirir. Gönderimde geçersiz bir alan varsa tarayıcı ilk geçersiz alanda varsayılan ya da sizin belirlediğiniz mesajı gösterir.
novalidate ve formnovalidate ile doğrulamayı kapatmak
Bazen doğrulamayı bilerek atlamak istersiniz. <form> öğesine yazılan novalidate Boolean özniteliği, formun gönderimde doğrulanmamasını söyler; yani etkileşimli doğrulama hiç yapılmaz. Bu, doğrulamayı tamamen kendi betiğinizle yapmak istediğinizde işe yarar. Daha yaygın ihtiyaç ise tek bir düğme için istisna tanımaktır. Bir gönder düğmesine (<button>, <input type="submit"> veya <input type="image">) yazılan formnovalidate, yalnızca o düğmeyle yapılan gönderimde doğrulamayı atlar.
<form action="/yazi" method="post">
<label for="baslik">Başlık</label>
<input id="baslik" name="baslik" type="text" required minlength="10" />
<button type="submit">Yayınla</button>
<!-- taslak yarım olabilir, bu düğme doğrulamayı atlar -->
<button type="submit" name="taslak" value="1" formnovalidate>Taslak olarak kaydet</button>
</form>Gönder düğmelerinin diğer form* öznitelikleri için button etiketi yazısına bakın. Aynı teknik, içinde zorunlu alan bulunan bir iletişim penceresini "İptal" düğmesiyle kapatırken de kullanılır; o örnek dialog etiketi yazısında.
Özel hata mesajı: setCustomValidity()
Tarayıcının varsayılan mesajları genel ifadelerdir. Kendi mesajınızı göstermek veya iki alanı karşılaştırmak gibi HTML ile ifade edilemeyen bir kural koymak için Constraint Validation API'deki setCustomValidity() metodunu kullanırsınız. Boş olmayan bir dize atandığında alan geçersiz sayılır ve o dize mesaj olarak gösterilir; boş dize atandığında hata kalkar. Aşağıdaki kısa betik MDN'deki örneğin Türkçeleştirilmiş hâlidir:
const kadi = document.querySelector("#kadi");
kadi.addEventListener("input", () => {
kadi.setCustomValidity(""); // önceki özel hatayı temizle
kadi.checkValidity(); // geçersizse invalid olayı tetiklenir
});
kadi.addEventListener("invalid", () => {
if (kadi.value === "") {
kadi.setCustomValidity("Lütfen bir kullanıcı adı yazın.");
} else {
kadi.setCustomValidity("Kullanıcı adı 3 ile 20 karakter olmalı.");
}
});Buradaki en kritik satır mesajı boş dizeye çeviren satırdır. MDN açıkça uyarır: özel hata bir kez atanıp temizlenmezse, kullanıcı değeri düzeltse bile alan geçersiz kalır ve form gönderilmez. Betik tarafı bu serinin kapsamı dışında; JavaScript temelleri için JavaScript öğrenme rehberine bakabilirsiniz. Alanların geçerli veya geçersiz görünümü ise CSS ile, :valid ve :invalid sözde sınıflarıyla değiştirilir.
Uygulamalı mini örnek: üyelik formu
Aşağıdaki form yazıdaki öznitelikleri bir araya getirir. Ad alanı zorunludur, e-posta türü sözdizimini denetler, şifre en az 8 karakterdir, yaş 18 ile 120 arasında bir tam sayı olmalıdır, kampanya kodu isteğe bağlıdır ama yazılırsa iki büyük harf ve dört rakamdan oluşmalıdır. Her kural etiket ya da yanındaki metinle görünür biçimde anlatılmıştır.
<form action="/uye-ol" method="post">
<p>
<label for="u-ad">Ad soyad (zorunlu)</label>
<input id="u-ad" name="ad" type="text" autocomplete="name" required />
</p>
<p>
<label for="u-eposta">E-posta (zorunlu)</label>
<input id="u-eposta" name="eposta" type="email" autocomplete="email" required />
</p>
<p>
<label for="u-sifre">Şifre (en az 8 karakter)</label>
<input id="u-sifre" name="sifre" type="password" minlength="8"
autocomplete="new-password" required />
</p>
<p>
<label for="u-yas">Yaş (18 ile 120 arası)</label>
<input id="u-yas" name="yas" type="number" min="18" max="120" step="1" required />
</p>
<p>
<label for="u-kod">Kampanya kodu (isteğe bağlı, örnek: AB1234)</label>
<input id="u-kod" name="kod" type="text" pattern="[A-Z]{2}[0-9]{4}"
title="İki büyük harf ve dört rakam" />
</p>
<button type="submit">Üye ol</button>
</form>Kampanya kodu boş bırakılırsa form gönderilir, çünkü alanda required yoktur. "ab1234" yazılırsa küçük harf ifadeye uymadığı için patternMismatch oluşur. Şifre alanındaki autocomplete="new-password" değerinin anlamı autocomplete ve şifre alanı yazısında anlatılıyor.
Sık yapılan hatalar

- Yalnızca istemci doğrulamasına güvenmek. HTML kuralları kullanıcıya hızlı geri bildirim içindir; güvenlik için değildir. Sunucu aynı kuralları tekrar uygulamalıdır.
patternilerequiredyerine geçmeye çalışmak. Boş değerpatterndenetimine girmez; zorunluluk için ayrıcarequiredgerekir.- Sayı alanında
patternkullanmak.type="number"bu özniteliği desteklemez. Basamak sınırınıminvemaxile verin ya da gerçek bir sayı değilsetype="text"veinputmode="numeric"kullanın. - Ondalık değer için
stepeklemeyi unutmak. Varsayılan adım 1 olduğundan 1,5 gibi değerler geçersiz kalır. minlengthdeğerinimaxlengthdeğerinden büyük vermek. Bu durumda alan hiçbir zaman geçerli olamaz.- Kuralı yalnızca
titleiçinde anlatmak. Kural görünür bir metin olarak etiketin içinde veya yanında yer almalıdır. setCustomValidity()mesajını temizlememek. Mesaj boş dizeye çekilmezse form kilitli kalır.
Form dışındaki geçersiz iç içe kullanım ve eksik etiket gibi genel hatalar için sık yapılan HTML hataları yazısına bakın.
Sık Sorulan Sorular
HTML form doğrulaması JavaScript olmadan çalışır mı?
Evet. required, pattern, minlength, maxlength, min, max, step ve type kuralları tarayıcı tarafından betik olmadan uygulanır. JavaScript yalnızca özel mesaj veya birden fazla alanı ilgilendiren kurallar için gerekir.
Neden boş bıraktığım e-posta alanı hata vermiyor?
Çünkü required dışındaki kısıtlar boş değerde çalışmaz. Alanın doldurulmasını istiyorsanız required ekleyin.
pattern içinde ^ ve $ yazmam gerekir mi?
Gerekmez. Tarayıcı değerin tamamının eşleşmesini zaten bekler. Yazarsanız da zarar vermez, ama eğik çizgi ve bayrak yazmayın.
novalidate ile formnovalidate arasındaki fark nedir?
novalidate forma yazılır ve o formun bütün gönderimlerinde doğrulamayı kapatır. formnovalidate bir gönder düğmesine yazılır ve yalnızca o düğmeyle yapılan gönderimde doğrulamayı atlar.
Doğrulama mesajlarının dilini nasıl değiştiririm?
Varsayılan mesajların metni tarayıcıya aittir. Kendi metninizi göstermek için setCustomValidity() kullanın ve değer düzeldiğinde mesajı boş dizeye çekmeyi unutmayın.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: HTML öğrenme rehberi · HTML form etiketi · input türleri · number ve range · tarih ve saat alanları · button etiketi · aria-describedby