---
title: 'Form Kalıpları'
source: 'https://academia.sh/tr/kurslar/erisilebilir-kaliplar/form-kaliplari'
course: 'Erişilebilir Bileşen Kalıpları'
language: tr
updated: '2026-08-17T18:09:33+00:00'
license: 'CC BY-SA 4.0'
---

# Form Kalıpları

Alan gruplamanın ölçütü, çok adımlı formda odak ve duyuru yönetimi, kaydetme ile geri alma davranışı ve iki düzenin kural denetimiyle karşılaştırılması.

Önceki dört ders bileşenleri tek tek belirtti. Ödünç alma formu ise bir düğme, üç alan, bir
seçenek grubu ve bir açılır liste taşır; her biri kendi başına doğru kurulmuş olsa bile
formun bütünü çalışmayabilir. Bir alanın hangi gruba ait olduğu, üç adıma bölünmüş bir
formda adımın değiştiğinin nasıl bildirileceği ve gönderimin geri alınıp alınamayacağı
bileşen belirtimlerinde yazmaz.

Bu ders formu bir bütün olarak belirtir. Ölçülen şey, tek tek doğru bileşenlerin bir arada
üretebildiği kusurlardır.

## Bölünme Ölçütü

Bir form, alan sayısı çok olduğu için bölünmez. Bölünme ölçütü, alanların **birbirinden
bağımsız karar kümeleri** oluşturmasıdır: ödünç alma formunda kayıt seçimi, üye bilgisi ve
süre kararı ayrı kümelerdir; her biri kendi başına doğrulanabilir ve kullanıcı birini
tamamlamadan diğerine geçmez.

Ölçüt sağlanmıyorsa bölmek zarar verir. Beş alanlı bir düzeltme bildirimi formunu üç sayfaya
yaymak, kullanıcının tamamını bir arada görmesini engeller ve her geçişte odak yönetimi
gerektiren bir yük ekler. Kısa formlar tek görünümde kalır.

## Alan Gruplama

Gruplamanın ölçütü, alanların **ortak bir soruya** yanıt vermesidir. "İade tarihi" ile
"Ödünç süresi" ortak bir soruya yanıt verir; "Üye numarası" ile "Ödünç süresi" vermez.
Ekranda birbirine yakın durmak gruplama gerekçesi değildir.

Ortak sorusu olan alanlar `fieldset` ve `legend` ile sarılır; grup adı sorunun kendisidir.
Yalnız bir alan taşıyan bir grup kurulmaz — o alanın etiketi zaten sorudur ve ek bir grup adı
duyuruyu iki kat uzatır.

```html
<h2 id="adim-2" tabindex="-1">Üye bilgisi</h2>
<p id="adim-durum" role="status">Adım 2 / 3</p>

<form action="/odunc/adim-2" method="post">
  <fieldset>
    <legend>Bildirim yöntemi</legend>
    <p><label><input type="radio" name="bildirim" value="eposta" checked> E-posta</label></p>
    <p><label><input type="radio" name="bildirim" value="yok"> Bildirim yok</label></p>
  </fieldset>

  <p><label for="uye-no">Üye numarası</label>
     <input id="uye-no" name="uye-no" required inputmode="numeric"
            aria-describedby="uye-yardim">
     <span id="uye-yardim">Kart üzerindeki 8 haneli numara.</span></p>

  <p><button type="submit">İleri</button>
     <button type="button" name="geri">Geri</button></p>
</form>
```

Düğmelerin sırası ve türü belirtimin parçasıdır. "İleri" düğmesi formun **ilk gönderim
düğmesidir**; bir metin alanındayken giriş tuşuna basan kullanıcı bu düğmeyi çalıştırır.
"Geri" düğmesi `type="button"` taşır; taşımazsa örtük gönderimde formu geriye götürür ve
kullanıcı bir adım kaybeder.

## Adım Değişimi Sayfa Değişimi Değildir

Sayfa yenilenerek yapılan bir geçişte odak belgenin başına döner ve kullanıcı yeni belgeye
baştan girer. Sayfa yenilenmeden yapılan bir geçişte hiçbir şey kendiliğinden olmaz: ekranda
içerik değişir, odak eski düğmede kalır, ekranı görmeyen kullanıcı için hiçbir şey olmamış
gibi görünür.

Belirtim üç şey ister: odak yeni adımın başlığına taşınır, geçiş kibar öncelikli bir durum
bölgesiyle duyurulur, adım göstergesi kaçıncı adımda olunduğunu metinle söyler. Başlığın
`tabindex="-1"` taşıması, sekme sırasına girmeden odak alabilmesi içindir.

Aşağıdaki betik aynı senaryoyu iki düzende koşturur ve dört kuralı denetler.

```js
// form.mjs — cok adimli formda odak yonetimi, duyuru ve deger korumasinin denetimi

const ADIMLAR = [
  { ad: "Kayıt onayı", baslik: "adim-1", alanlar: [
    { id: "kayit", etiket: "Kayıt numarası", zorunlu: true,
      kural: (v) => /^K-\d{3}$/.test(v), ileti: "Kayıt numarası K-000 biçiminde olmalı." },
  ] },
  { ad: "Üye bilgisi", baslik: "adim-2", alanlar: [
    { id: "uye-no", etiket: "Üye numarası", zorunlu: true,
      kural: (v) => /^\d{8}$/.test(v), ileti: "Üye numarası 8 hane olmalı." },
    { id: "eposta", etiket: "Bildirim adresi", zorunlu: false,
      kural: (v) => v === "" || v.includes("@"), ileti: "Geçerli bir e-posta adresi yazın." },
  ] },
  { ad: "Süre ve onay", baslik: "adim-3", alanlar: [
    { id: "sure", etiket: "Ödünç süresi", zorunlu: true,
      kural: (v) => ["14", "21", "28"].includes(v), ileti: "Bir ödünç süresi seçin." },
  ] },
];

const baslangic = () => ({
  adim: 0, degerler: {}, hatalar: [], odak: "input#kayit", duyuru: "", bitti: false,
});

function dogrula(adim, degerler) {
  const h = [];
  for (const a of ADIMLAR[adim].alanlar) {
    const v = degerler[a.id] ?? "";
    if (a.zorunlu && v === "") h.push([a.id, a.etiket, "Bu alan zorunludur."]);
    else if (v !== "" && !a.kural(v)) h.push([a.id, a.etiket, a.ileti]);
  }
  return h;
}

// duzen: odagiTasi, gecisiDuyur, degerleriKoru
function makine(duzen) {
  const odak = (hedef, eski) => (duzen.odagiTasi ? hedef : eski);
  const duyur = (m) => (duzen.gecisiDuyur ? m : "");
  return (d, e) => {
    if (e.tur === "yaz") return { ...d, degerler: { ...d.degerler, [e.id]: e.deger } };
    if (e.tur === "geri") {
      if (d.adim === 0) return d;
      const y = d.adim - 1;
      return { ...d, adim: y, hatalar: [],
        degerler: duzen.degerleriKoru ? d.degerler : {},
        odak: odak("h2#" + ADIMLAR[y].baslik, d.odak),
        duyuru: duyur(`Adım ${y + 1} / ${ADIMLAR.length}: ${ADIMLAR[y].ad}`) };
    }
    if (e.tur === "ileri" || e.tur === "gonder") {
      const hatalar = dogrula(d.adim, d.degerler);
      if (hatalar.length > 0) {
        return { ...d, hatalar, odak: odak("div#hata-ozeti", d.odak),
          duyuru: duyur(`${hatalar.length} alan düzeltilmeli`) };
      }
      if (e.tur === "gonder" && d.adim === ADIMLAR.length - 1) {
        return { ...d, hatalar: [], bitti: true, odak: odak("h2#sonuc", d.odak),
          duyuru: duyur("Ödünç alma isteği kaydedildi") };
      }
      const y = Math.min(d.adim + 1, ADIMLAR.length - 1);
      return { ...d, adim: y, hatalar: [],
        odak: odak("h2#" + ADIMLAR[y].baslik, d.odak),
        duyuru: duyur(`Adım ${y + 1} / ${ADIMLAR.length}: ${ADIMLAR[y].ad}`) };
    }
    return d;
  };
}

const SENARYO = [
  { tur: "yaz", id: "kayit", deger: "K-118" },
  { tur: "ileri" },
  { tur: "yaz", id: "uye-no", deger: "1234" },
  { tur: "ileri" },
  { tur: "yaz", id: "uye-no", deger: "10045512" },
  { tur: "ileri" },
  { tur: "geri" },
  { tur: "ileri" },
  { tur: "yaz", id: "sure", deger: "21" },
  { tur: "gonder" },
];

const ODAKLANABILIR = new Set([
  "input#kayit", "div#hata-ozeti", "h2#adim-1", "h2#adim-2", "h2#adim-3", "h2#sonuc",
]);

function kosum(baslik, duzen, izYaz) {
  const sonraki = makine(duzen);
  let d = baslangic();
  const iz = [];
  console.log(baslik);
  if (izYaz) console.log("  eylem".padEnd(24) + "adim".padEnd(18) + "odak".padEnd(18) + "duyuru");
  for (const e of SENARYO) {
    const onceki = d;
    d = sonraki(d, e);
    iz.push({ e, onceki, d });
    if (!izYaz) continue;
    const etiket = e.tur === "yaz" ? `yaz ${e.id}` : e.tur;
    const adimAdi = d.bitti ? "sonuc" : `${d.adim + 1}/${ADIMLAR.length} ${ADIMLAR[d.adim].ad}`;
    console.log("  " + etiket.padEnd(22) + adimAdi.padEnd(18) + d.odak.padEnd(18) +
      (d.duyuru || "-"));
  }

  const bulgular = [];
  for (const { e, onceki, d: s } of iz) {
    if (e.tur === "yaz") continue;
    if (s.odak === onceki.odak && s.adim !== onceki.adim)
      bulgular.push(`${e.tur}: adim degisti, odak tasinmadi`);
    if (s.hatalar.length > 0 && s.odak !== "div#hata-ozeti")
      bulgular.push(`${e.tur}: hata var, odak ozete tasinmadi`);
    if (!ODAKLANABILIR.has(s.odak))
      bulgular.push(`${e.tur}: odak hedefi odaklanabilir degil (${s.odak})`);
    if (s.duyuru === "") bulgular.push(`${e.tur}: gecis duyurulmadi`);
    for (const k of Object.keys(onceki.degerler)) {
      if (onceki.degerler[k] !== s.degerler[k])
        bulgular.push(`${e.tur}: ${k} alaninin degeri kayboldu`);
    }
  }
  console.log(`  bulgu: ${bulgular.length}`);
  for (const b of bulgular) console.log("    " + b);
  return iz;
}

kosum("kusurlu duzen (odak tasinmiyor, gecis duyurulmuyor, geri gidiste degerler siliniyor):",
  { odagiTasi: false, gecisiDuyur: false, degerleriKoru: false }, false);

console.log("");
const iz = kosum("duzeltilmis duzen:",
  { odagiTasi: true, gecisiDuyur: true, degerleriKoru: true }, true);

const hatali = iz.find(({ d }) => d.hatalar.length > 0).d;
console.log("\nhatali gecisteki ozet baglantilari:");
for (const [id, etiket, ileti] of hatali.hatalar) {
  console.log(`  <a href="#${id}">${etiket}: ${ileti}</a>`);
}
```

```
kusurlu duzen (odak tasinmiyor, gecis duyurulmuyor, geri gidiste degerler siliniyor):
  bulgu: 14
    ileri: adim degisti, odak tasinmadi
    ileri: gecis duyurulmadi
    ileri: hata var, odak ozete tasinmadi
    ileri: gecis duyurulmadi
    ileri: adim degisti, odak tasinmadi
    ileri: gecis duyurulmadi
    geri: adim degisti, odak tasinmadi
    geri: gecis duyurulmadi
    geri: kayit alaninin degeri kayboldu
    geri: uye-no alaninin degeri kayboldu
    ileri: hata var, odak ozete tasinmadi
    ileri: gecis duyurulmadi
    gonder: hata var, odak ozete tasinmadi
    gonder: gecis duyurulmadi

duzeltilmis duzen:
  eylem                 adim              odak              duyuru
  yaz kayit             1/3 Kayıt onayı   input#kayit       -
  ileri                 2/3 Üye bilgisi   h2#adim-2         Adım 2 / 3: Üye bilgisi
  yaz uye-no            2/3 Üye bilgisi   h2#adim-2         Adım 2 / 3: Üye bilgisi
  ileri                 2/3 Üye bilgisi   div#hata-ozeti    1 alan düzeltilmeli
  yaz uye-no            2/3 Üye bilgisi   div#hata-ozeti    1 alan düzeltilmeli
  ileri                 3/3 Süre ve onay  h2#adim-3         Adım 3 / 3: Süre ve onay
  geri                  2/3 Üye bilgisi   h2#adim-2         Adım 2 / 3: Üye bilgisi
  ileri                 3/3 Süre ve onay  h2#adim-3         Adım 3 / 3: Süre ve onay
  yaz sure              3/3 Süre ve onay  h2#adim-3         Adım 3 / 3: Süre ve onay
  gonder                sonuc             h2#sonuc          Ödünç alma isteği kaydedildi
  bulgu: 0

hatali gecisteki ozet baglantilari:
  <a href="#uye-no">Üye numarası: Üye numarası 8 hane olmalı.</a>
```

Kusurlu düzen on dört bulgu üretiyor ve bunların ikisi zincirleme kusurdur: geri gidişte
değerler silindiği için sonraki iki geçiş de doğrulamadan geçemiyor. Ekranda görülen tek şey
"formun geri dönünce boşalması"dır; kalan on iki bulgu ekranda hiç görünmez.

Düzeltilmiş koşumun izinde iki satır dikkat gerektirir. Dördüncü satırda doğrulama
başarısız oluyor ve odak hata özetine gidiyor; adım numarası değişmiyor. Yedinci satırda
geri gidiş de bir adım değişimidir ve ileri gidişle **aynı** odak ve duyuru işlemini
gerektirir; geri gidişin sessiz bırakılması sık atlanan bir durumdur.

## Klavye Sözleşmesi

| Tuş | Davranış |
|---|---|
| `Tab` / `Shift+Tab` | Alanlar arasında kaynak sırasıyla gezer. |
| `Enter` (tek satırlık alanda) | Formun ilk gönderim düğmesini çalıştırır. |
| `Enter` (çok satırlı alanda) | Satır sonu ekler; form göndermez. |
| `Enter` (düğmede) | Odaktaki düğmeyi çalıştırır. |

Sözleşmenin kısıtı, örtük gönderimin **hangi düğmeyi** çalıştıracağıdır. Formun ilk gönderim
düğmesi "Geri" ise, alanda giriş tuşuna basan kullanıcı bir adım geriye düşer. Gönderim
niteliği taşımayan her düğme `type="button"` yazılır.

## Kaydetme ve Geri Alma

Ödünç alma isteği bir kayıt üretir; kullanıcının kendi verisi üzerinde bağlayıcı bir işlemdir.
3.3.4 Hata Önleme ölçütü bu tür gönderimlerde üç yoldan **en az birini** ister: gönderim geri
alınabilir olmalı, girilen veri denetlenip düzeltilebilmeli, ya da gönderim öncesinde
onaylanmalıdır.

Üç adımlı formda ikinci yol kendiliğinden kurulur: son adım, girilen bütün değerleri özet
olarak gösterir ve her satırın yanında ilgili adıma dönen bir bağlantı taşır. Özetin salt
metin olması yetmez; kullanıcı düzeltmek istediği alana bir eylemle ulaşabilmelidir.

İki ek kural belirtimde yazılır. Kaydedilmemiş değişiklik varken sayfadan ayrılmak
uyarıyla karşılanır; uyarı bir kip pencere olduğunda odak yönetimi gerektirir ve bu, sonraki
konunun sorumluluğudur. Oturum zaman aşımı varsa 2.2.1 Zamanlamanın Ayarlanabilirliği
devreye girer: kullanıcı süreyi uzatabilmeli ya da veri korunmalıdır. Yirmi dakikada
dolan bir oturumun uzun bir formu sessizce silmesi bu ölçütü kaldırır.

## Ölçülebilir Kısıtlar

**3.3.2 Etiketler ve Yönergeler** her alanda etiket ya da yönerge ister; **3.3.1 Hata
Belirleme** hatalı alanın metinle belirtilmesini; **3.3.3 Hata Önerisi** biliniyorsa
düzeltme önerisinin verilmesini ister. Denetimdeki "Üye numarası 8 hane olmalı" iletisi bu
üçüncü ölçütün karşılığıdır: hatayı bildirmekle kalmaz, doğru biçimi söyler.

**1.3.5 Girdi Amacını Belirleme**, kullanıcının kendi bilgisini toplayan alanlarda amacın
program yoluyla bildirilmesini ister; ödünç alma formunda ad ve bildirim adresi alanları bu
kapsamdadır.

**2.4.6 Başlıklar ve Etiketler** adım başlıklarının içeriği gerçekten tanımlamasını ister:
"Adım 2" bir başlık değildir, "Üye bilgisi" başlıktır ve adım numarası ayrı bir metinle
verilir.

## Sık Yapılan Hata

**Adım göstergesinin yalnızca görsel olması.** Dolan bir çubuk ya da renklenen üç nokta,
ekranı görmeyen kullanıcıya hiçbir şey söylemez. Saptaması, göstergenin metin karşılığının
ağaçta bulunup bulunmadığının denetlenmesidir.

**Hata özetinin bulunduğu yerde bırakılması.** Özet oluşturulup odak taşınmadığında kullanıcı
gönderimin başarısız olduğunu öğrenemez. Saptaması denetimin ikinci kuralıdır: hata varken
odağın özete taşınıp taşınmadığı sınanır.

**Geri gidişin sessiz bırakılması.** İleri gidişte kurulan odak ve duyuru düzeni geri gidişte
de gereklidir. Saptaması, iki yönün aynı kural kümesinden geçirilmesidir.

**Tek alanlı grup kurulması.** Bir alanı `fieldset` içine almak, alanın adını grup adıyla
birlikte iki kez duyurur. Saptaması, grup içindeki alan sayısının sayılmasıdır.

## Özet

- Form, alan sayısına göre değil bağımsız karar kümelerine göre bölünür; kısa formlar tek
  görünümde kalır.
- Gruplamanın ölçütü alanların ortak bir soruya yanıt vermesidir; tek alanlı grup kurulmaz.
- Adım değişimi üç işlem gerektirir: odağın yeni adım başlığına taşınması, geçişin kibar
  öncelikle duyurulması ve adım göstergesinin metinle verilmesi. Geri gidiş de bir adım
  değişimidir.
- Formun ilk gönderim düğmesi örtük gönderimde çalışır; gönderim niteliği taşımayan
  düğmeler `type="button"` yazılır.
- 3.3.4 bağlayıcı gönderimlerde geri alma, düzeltme ya da onaylama yollarından en az birini
  ister; son adımdaki düzeltilebilir özet ikinci yolu kurar.
- Denetimin ürettiği bulguların çoğu ekranda görünmez; odak ve duyuru kusurları yalnızca
  kural sınamasıyla ortaya çıkar.

## Sonraki Adım

Bu konudaki bütün bileşenler bir eylemi çalıştırdı: aramayı koşturmak, süzgeci uygulamak,
formu göndermek. Sonuç tablosundaki kayıt başlıkları ise farklı bir iş yapar — kullanıcıyı
başka bir kaynağa götürür. İkisi ekranda birbirine benzetilebilir, ancak klavye
sözleşmeleri, ağaçtaki rolleri ve kullanıcının onlardan beklediği şey ayrıdır. Sonraki ders
bu ayrımı kurala bağlar ve karışmanın hangi somut kırılmaları ürettiğini gösterir.
