Formlar · Alanlar ve doğrulama
Formlar, sürtünmesiz.
Her alan aynı yapıyı izler: etiket, alan, ipucu ve hata. Doğrulama tarayıcının yerleşik kurallarını kullanır, mesajları Türkçeleştirir.
01Alan yapısı#
Her alan bir fk-field içinde durur. Etiket for ile alana bağlanır; hata mesajı fk-error içinde gösterilir.
<div class="fk-field" style="width:100%;max-width:420px">
<label class="fk-label" for="f-ad">Ad Soyad <span class="fk-req">*</span></label>
<input type="text" class="fk-input" id="f-ad" name="ad" placeholder="Furkan Kırcı" required>
<span class="fk-hint">Faturada görünecek ad.</span>
<span class="fk-error" role="alert"></span>
</div>| Sınıf / öznitelik | Açıklama |
|---|---|
fk-form | Alanları 20px aralıkla dizen ızgara |
fk-form-row | Yan yana 2 alan; telefonda alt alta |
fk-field | Tek alanın kapsayıcısı; hata durumunda is-invalid alır |
fk-label / fk-req | Etiket / zorunlu yıldızı |
fk-hint / fk-error | Yardım metni / hata metni |
02Input, select ve textarea#
<div class="fk-form" style="width:100%">
<div class="fk-form-row">
<div class="fk-field"><label class="fk-label" for="f-mail">E-posta</label><input class="fk-input" id="f-mail" type="email" placeholder="ornek@mail.com"></div>
<div class="fk-field"><label class="fk-label" for="f-konu">Konu</label><select class="fk-select" id="f-konu"><option>Proje</option><option>İş başvurusu</option><option>Diğer</option></select></div>
</div>
<div class="fk-field"><label class="fk-label" for="f-mesaj">Mesaj</label><textarea class="fk-textarea" id="f-mesaj" placeholder="Kısaca anlat…"></textarea></div>
<div class="fk-field"><label class="fk-label" for="f-pasif">Pasif alan</label><input type="text" class="fk-input" id="f-pasif" value="Değiştirilemez" disabled></div>
</div>03İkonlu alan ve şifre#
<div class="fk-form" style="width:100%;max-width:420px">
<div class="fk-field">
<label class="fk-label" for="f-ara">Ara</label>
<div class="fk-input-group"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg><input class="fk-input" id="f-ara" type="search" placeholder="Dosya ara…"></div>
</div>
<div class="fk-field">
<label class="fk-label" for="f-sifre">Şifre</label>
<div class="fk-input-group"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5" y="11" width="14" height="10" rx="2.5"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg><input class="fk-input" id="f-sifre" type="password" value="gizli1234"><button class="fk-btn fk-btn-icon" type="button" data-fk-password aria-label="Şifreyi göster"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12Z"/><circle cx="12" cy="12" r="3"/></svg></button></div>
</div>
</div>| Sınıf / öznitelik | Açıklama |
|---|---|
fk-input-group | Soldaki SVG ikonu ve sağdaki butonu alanın içine yerleştirir |
data-fk-password | Şifreyi göster/gizle |
04Boyutlar, ön ek ve kopyalama alanı#
<div class="fk-form" style="width:100%;max-width:520px">
<input type="text" class="fk-input fk-input-sm" placeholder="Küçük alan" aria-label="Küçük alan">
<input type="text" class="fk-input" placeholder="Normal alan" aria-label="Normal alan">
<input type="text" class="fk-input fk-input-lg" placeholder="Büyük alan" aria-label="Büyük alan">
<div class="fk-field">
<label class="fk-label" for="f-sub">Alt alan adı</label>
<div class="fk-affix"><span>https://</span><input type="text" class="fk-input" id="f-sub" placeholder="projem"><span>.fkdev.sbs</span></div>
</div>
<div class="fk-copyfield">
<input type="text" id="f-cdn" value="https://ui.fkdev.sbs/v2.4.1/fkdev-ui.min.css" readonly aria-label="CDN adresi">
<button type="button" class="fk-btn fk-btn-primary fk-btn-sm" data-fk-copy="#f-cdn" data-fk-msg="CDN adresi kopyalandı"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2.5"/><path d="M15 9V6.5A2.5 2.5 0 0 0 12.5 4h-6A2.5 2.5 0 0 0 4 6.5v6A2.5 2.5 0 0 0 6.5 15H9"/></svg>Kopyala</button>
</div>
</div>| Sınıf / öznitelik | Açıklama |
|---|---|
fk-input-sm / fk-input-lg | Küçük ve büyük alan |
fk-affix | Alanın önüne/arkasına sabit metin (birim, alan adı, para birimi) |
fk-copyfield | Salt okunur değer + kopyala butonu; data-fk-copy="#id" alanın değerini kopyalar |
05Karakter sayacı#
<div class="fk-field" data-fk-counter style="width:100%;max-width:520px">
<label class="fk-label" for="f-bio">Kısa biyografi</label>
<textarea class="fk-textarea" id="f-bio" maxlength="160" placeholder="160 karakterde kendini anlat…"></textarea>
<span class="fk-counter"></span>
</div>Alanı kapsayan öğeye data-fk-counter ekle; sınır maxlength’ten okunur. Sınırın %90’ında sayaç sarıya, sınırda kırmızıya döner.
06Doğrulama kodu (OTP)#
<div class="fk-otp" role="group" aria-label="6 haneli doğrulama kodu">
<input type="text" aria-label="1. hane"><input type="text" aria-label="2. hane"><input type="text" aria-label="3. hane"><input type="text" aria-label="4. hane"><input type="text" aria-label="5. hane"><input type="text" aria-label="6. hane">
<input type="hidden" name="kod">
</div>Yazınca sonraki kutuya geçer, silince geri döner, yapıştırılan kodu kutulara dağıtır, telefonda SMS kodunu otomatik önerir. Tüm haneler dolunca fk:complete olayı tetiklenir ve kod gizli alana yazılır.
document.querySelector('.fk-otp').addEventListener('fk:complete', (e) => {
fetch('/api/dogrula', { method: 'POST', body: new URLSearchParams({ kod: e.detail.value }) });
});07Sayı seçici (stepper)#
<div class="fk-stepper">
<button type="button" aria-label="Azalt">−</button>
<input type="number" value="1" min="1" max="10" aria-label="Adet">
<button type="button" aria-label="Artır">+</button>
</div>min, max ve step öznitelikleri dikkate alınır; değişince change olayı tetiklenir.
08Etiket girişi#
<div class="fk-field" style="width:100%;max-width:520px">
<label class="fk-label" for="f-tags">Yetkinlikler</label>
<div class="fk-tags" data-fk-tags>
<span class="fk-tag">React<button type="button" class="fk-tag-x" aria-label="React etiketini kaldır">×</button></span>
<span class="fk-tag">Node.js<button type="button" class="fk-tag-x" aria-label="Node.js etiketini kaldır">×</button></span>
<input type="text" id="f-tags" placeholder="Yaz ve Enter’a bas…">
<input type="hidden" name="yetkinlikler">
</div>
<span class="fk-hint">Enter ya da virgül ile ekle, Backspace ile sonuncuyu sil.</span>
</div>09Checkbox, radio, switch, range#
<div class="fk-form" style="width:100%">
<div class="fk-cluster"><label class="fk-check"><input type="checkbox" checked> Bülteni al</label><label class="fk-check"><input type="checkbox"> Kampanyalar</label></div>
<div class="fk-cluster" role="radiogroup" aria-label="Plan"><label class="fk-radio"><input type="radio" name="plan" checked> Aylık</label><label class="fk-radio"><input type="radio" name="plan"> Yıllık</label></div>
<label class="fk-switch"><input type="checkbox" role="switch" checked> Karanlık mod</label>
<div class="fk-field"><label class="fk-label" for="f-butce">Bütçe</label><input class="fk-range" id="f-butce" type="range" min="0" max="100" value="60"></div>
</div>| Sınıf / öznitelik | Açıklama |
|---|---|
label.fk-check > input[type=checkbox] | Yaylanan onay işaretli kutu |
label.fk-radio > input[type=radio] | Radyo düğmesi |
label.fk-switch > input[role=switch] | Açma/kapama anahtarı |
input.fk-range | Kaydırıcı |
10Dosya yükleme#
<label class="fk-drop" style="width:100%">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 18a5 5 0 1 1 .9-9.9A6 6 0 0 1 19 10a4 4 0 0 1-1 8H7Z"/><path d="M12 11v6M9.5 13.5 12 11l2.5 2.5"/></svg>
<strong>Dosyanı buraya sürükle</strong>
<small>ya da tıkla · en fazla 150 MB</small>
<input type="file" name="dosya">
<span class="fk-drop-file" aria-live="polite"></span>
</label>Seçilen dosyanın adı ve boyutu fk-drop-file içine otomatik yazılır. Sunucu tarafı için PHP form işleme ve dosyalar tablosu için veritabanı şemasına bak.
11Doğrulama#
Forma data-fk-validate ekle. Alanlar odaktan çıkınca kontrol edilir; gönderirken hatalı ilk alana odaklanılır ve bildirim gösterilir. Kurallar yerleşik HTML öznitelikleridir: required, type="email", minlength, pattern…
<form class="fk-form" data-fk-validate data-fk-demo data-fk-success="Mesajın iletildi, teşekkürler!" style="width:100%;max-width:520px">
<div class="fk-form-row">
<div class="fk-field"><label class="fk-label" for="v-ad">Ad <span class="fk-req">*</span></label><input type="text" class="fk-input" id="v-ad" required minlength="2" data-fk-msg="Adını en az 2 harf yaz."><span class="fk-error"></span></div>
<div class="fk-field"><label class="fk-label" for="v-mail">E-posta <span class="fk-req">*</span></label><input class="fk-input" id="v-mail" type="email" required data-fk-msg="Geçerli bir e-posta yaz."><span class="fk-error"></span></div>
</div>
<div class="fk-field"><label class="fk-label" for="v-msg">Mesaj <span class="fk-req">*</span></label><textarea class="fk-textarea" id="v-msg" required minlength="10" data-fk-msg="Mesaj en az 10 karakter olmalı."></textarea><span class="fk-error"></span></div>
<label class="fk-check"><input type="checkbox" required> KVKK metnini okudum</label>
<button class="fk-btn fk-btn-primary" type="submit">Gönder <svg class="fk-go" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></button>
</form>| Sınıf / öznitelik | Açıklama |
|---|---|
form[data-fk-validate] | Doğrulamayı açar (tarayıcı balonlarını kapatır) |
data-fk-msg | Alan için özel hata mesajı |
data-fk-error | Form genel hata bildirimi |
data-fk-demo | Sadece demo: gerçekten göndermez, başarı bildirimi gösterir |
data-fk-success | Demo başarı mesajı |
Sunucuda da doğrulaTarayıcı doğrulaması kullanıcı deneyimi içindir; güvenlik değildir. Her alanı sunucuda yeniden kontrol et.
12Tam örnek: giriş formu#
Tekrar hoş geldin.
<div class="fk-card" style="width:100%;max-width:420px">
<h3 class="fk-card-title" style="text-align:center">Tekrar <em>hoş geldin.</em></h3>
<form class="fk-form" data-fk-validate data-fk-demo data-fk-success="Giriş başarılı (demo)" style="margin-top:20px">
<div class="fk-field"><label class="fk-label" for="g-mail">E-posta</label><div class="fk-input-group"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="3"/><path d="m4 7 8 6 8-6"/></svg><input class="fk-input" id="g-mail" type="email" autocomplete="email" required data-fk-msg="E-postanı yaz."></div><span class="fk-error"></span></div>
<div class="fk-field"><label class="fk-label" for="g-pass">Şifre</label><div class="fk-input-group"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5" y="11" width="14" height="10" rx="2.5"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg><input class="fk-input" id="g-pass" type="password" autocomplete="current-password" required minlength="8" data-fk-msg="Şifre en az 8 karakter."><button class="fk-btn fk-btn-icon" type="button" data-fk-password aria-label="Şifreyi göster"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12Z"/><circle cx="12" cy="12" r="3"/></svg></button></div><span class="fk-error"></span></div>
<label class="fk-check"><input type="checkbox"> Beni hatırla</label>
<button class="fk-btn fk-btn-primary fk-btn-block" type="submit">Giriş yap</button>
</form>
</div>13Formu sunucuya gönderme#
Formu sayfayı yenilemeden göndermek için fetch kullan; sonucu FK.toast ile göster.
document.querySelector('#iletisim').addEventListener('submit', async (e) => {
e.preventDefault();
const form = e.currentTarget;
const btn = form.querySelector('[type="submit"]');
btn.classList.add('is-loading');
try {
const res = await fetch('/api/iletisim.php', { method: 'POST', body: new FormData(form) });
const data = await res.json();
if (!res.ok || !data.ok) throw new Error(data.error || 'Gönderilemedi');
form.reset();
FK.toast('Mesajın iletildi!', 'success');
} catch (err) {
FK.toast(err.message, 'danger');
} finally {
btn.classList.remove('is-loading');
}
});PHP tarafı (doğrulama, CSRF, veritabanına yazma) için Framework & PHP sayfasına geç.