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

# Akordeon

Aşamalı gösterimin kalıbı, yerel açılıp kapanan panel ögesiyle elle kurulan akordeonun karşılaştırılması, genişleme durumunun izlenmesi ve yapısal kural denetimi.

Sekme kalıbı bir kısıt taşıyordu: aynı anda yalnız bir bölüm görünür. Kayıt ayrıntısı
sayfasının alt kısmındaki "Baskılar", "Konu başlıkları" ve "Benzer kayıtlar" bölümleri için
bu kısıt gereksizdir. Kullanıcı üçünü birden açık tutmak isteyebilir; hiçbirini açmadan da
sayfayı okuyup ayrılabilir.

Kısıtsız çözüm akordeondur ve tek bir durum bildirimine dayanır: bölüm şu anda genişletilmiş
mi? Bu ders o tek bildirimi belirtir ve güncellenmemesinin neden en sık üretilen kusur
olduğunu gösterir.

## Kalıbın Çözdüğü Sorun

Akordeon, **ikincil içeriğin** sayfayı uzatmasını engeller. Ölçüt ikincillıktir: kullanıcıların
çoğu o bölümü açmadan işini tamamlıyorsa bölüm katlanabilir.

Ölçüt sağlanmadığında kalıp zarar verir. Kaydın raf konumu, ödünç alınabilirlik durumu ve
iade tarihi zorunlu bilgilerdir; katlandıklarında kullanıcı bir tuş vuruşu daha yapmak
zorunda kalır ve bilginin var olduğunu göremez.

İki ek sınır vardır. Kapalı bir bölümün içeriği belgede gizlidir; kullanıcının sayfa içinde
arayarak bulmasını gerektiren bilgi akordeona konmaz. İkincisi, iki ya da üç kısa
paragraflık içeriği katlamak kazanç sağlamaz — açma eylemi, kazanılan yerden daha pahalıdır.

## Yerel Öge Önce

Bu kalıbın yerel karşılığı **vardır**: `details` ve `summary` ögeleri. `summary` ögesi
açma denetimidir, `details` ögesi kapsayıcıdır ve açık olup olmadığı `open` özniteliğinden
okunur.

Getirdikleri şunlardır: açma ve kapama davranışı, denetimin odaklanabilirliği, giriş ve
boşluk tuşlarıyla çalıştırılabilirlik ve genişleme durumunun ağaca bildirimi. Hiçbiri
ayrıca yazılmaz. `details` ögelerine ortak bir ad verildiğinde aynı anda yalnız birinin
açık kalması da tanımlıdır; bu davranış gerekiyorsa yetenek saptamasıyla sınanır ve
karşılanmadığında elle kurulur.

Bedeli iki yerdedir: açma imleyicisinin görünümünün sunum katmanından denetlenmesi
sınırlıdır ve açılma hareketine geçiş uygulanması kolay değildir. Katalogun kayıt ayrıntısı
sayfasında bu bedel ödenebilir.

## Elle Kurulan Akordeon

Yerel ögenin karşılamadığı bir gereksinim varsa kalıp bir düğmeyle kurulur.

```html
<h3>
  <button aria-expanded="true" aria-controls="panel-baski" id="baslik-baski">
    Baskılar
  </button>
</h3>
<div id="panel-baski" role="region" aria-labelledby="baslik-baski">…</div>

<h3>
  <button aria-expanded="false" aria-controls="panel-konu" id="baslik-konu">
    Konu başlıkları
  </button>
</h3>
<div id="panel-konu" role="region" aria-labelledby="baslik-konu" hidden>…</div>
```

Üç karar bağlayıcıdır. Düğme bir **başlık ögesinin içindedir**; başlık düğmenin içine değil,
düğme başlığın içine yazılır. Böylece bölüm adı ana hatta girer ve kullanıcı başlık
listesinden bölümler arasında gezinebilir. Başlık düzeyi, çevresindeki ana hatta göre
seçilir; akordeonun kendisi bir düzey dayatmaz.

`aria-expanded` durumu düğmeye yazılır, panele değil: genişleten şey düğmedir. Panelin
`role="region"` bildirimi ve `aria-labelledby` bağı, bölümün yer imi listesinde
bulunabilmesini sağlar; bölüm sayısı çoksa bu liste kalabalıklaşır ve bildirim
uygulanmayabilir.

Açma imleyicisi olarak kullanılan ok simgesi sunumsaldır; durumu simge değil,
`aria-expanded` bildirir.

## Genişleme Durumunun İzlenmesi

```js
// akordeon.mjs — genisleme durumunun izlenmesi ve yapisal kural denetimi

const BOLUMLER = ["Baskılar", "Konu başlıkları", "Benzer kayıtlar"];

// kip: "coklu" (bagimsiz) | "tekli" (ayni anda bir bolum)
const baslangic = (kip) => ({ kip, acik: new Set() });

function calistir(d, i) {
  const a = new Set(d.acik);
  if (a.has(i)) a.delete(i);
  else if (d.kip === "tekli") { a.clear(); a.add(i); }
  else a.add(i);
  return { ...d, acik: a };
}

// Isaretlemenin uretecegi durum: dugmede aria-expanded, panelde hidden
const uretilen = (d) =>
  BOLUMLER.map((ad, i) => ({ ad, "aria-expanded": d.acik.has(i), panelGorunur: d.acik.has(i) }));

function iz(kip, dizi) {
  let d = baslangic(kip);
  console.log(`\n${kip} kip:`);
  console.log("  calistirilan".padEnd(22) + "aria-expanded".padEnd(24) + "gorunur panel");
  console.log("  " + "(baslangic)".padEnd(20) +
    uretilen(d).map((o) => (o["aria-expanded"] ? "1" : "0")).join(" ").padEnd(24) +
    uretilen(d).filter((o) => o.panelGorunur).length);
  for (const i of dizi) {
    d = calistir(d, i);
    const u = uretilen(d);
    console.log("  " + BOLUMLER[i].padEnd(20) +
      u.map((o) => (o["aria-expanded"] ? "1" : "0")).join(" ").padEnd(24) +
      u.filter((o) => o.panelGorunur).length);
  }
  return d;
}

iz("coklu", [0, 1, 2, 1]);
const tekli = iz("tekli", [0, 1, 2, 2]);

// Degismez: bildirilen durum ile gorunurluk her zaman ortusur; tekli kipte en cok bir panel
console.log("\ndegismez taramasi:");
let durum = 0, kirilma = 0;
for (const kip of ["coklu", "tekli"]) {
  const gorulen = new Set();
  const kuyruk = [baslangic(kip)];
  const anahtar = (d) => [...d.acik].sort().join(",");
  gorulen.add(anahtar(kuyruk[0]));
  while (kuyruk.length) {
    const d = kuyruk.shift();
    durum++;
    const u = uretilen(d);
    if (u.some((o) => o["aria-expanded"] !== o.panelGorunur)) kirilma++;
    if (kip === "tekli" && u.filter((o) => o.panelGorunur).length > 1) kirilma++;
    for (let i = 0; i < BOLUMLER.length; i++) {
      const y = calistir(d, i);
      if (gorulen.has(anahtar(y))) continue;
      gorulen.add(anahtar(y));
      kuyruk.push(y);
    }
  }
}
console.log(`  taranan durum: ${durum}, degismez kirilmasi: ${kirilma}`);
console.log(`  tekli kipte ulasilan durum sayisi: ${BOLUMLER.length + 1}`);

// --- Yapisal kural denetimi -------------------------------------------------
// Her kayit: baslik dugmesinin sarildigi oge, aria-controls hedefi, panel gizliligi
const ISARETLEME = [
  { ad: "Baskılar", sarmalayan: "h3", controls: "panel-baski",
    genisletilmis: true, panelGizli: false, paneller: ["panel-baski"] },
  { ad: "Konu başlıkları", sarmalayan: "div", controls: "panel-konu",
    genisletilmis: false, panelGizli: true, paneller: ["panel-konu"] },
  { ad: "Benzer kayıtlar", sarmalayan: "h3", controls: "panel-benzer-2",
    genisletilmis: true, panelGizli: true, paneller: ["panel-benzer"] },
];
const BASLIK_OGELERI = new Set(["h1", "h2", "h3", "h4", "h5", "h6"]);
const VAR_OLAN = new Set(["panel-baski", "panel-konu", "panel-benzer"]);

console.log("\nyapisal kural denetimi:");
let bulgu = 0;
for (const k of ISARETLEME) {
  const b = [];
  if (!BASLIK_OGELERI.has(k.sarmalayan))
    b.push(`baslik dugmesi bir baslik ogesi icinde degil (${k.sarmalayan})`);
  if (!VAR_OLAN.has(k.controls))
    b.push(`aria-controls var olmayan bir kimlige isaret ediyor (${k.controls})`);
  if (k.genisletilmis === k.panelGizli)
    b.push(`aria-expanded=${k.genisletilmis} ama panel ${k.panelGizli ? "gizli" : "gorunur"}`);
  for (const x of b) { bulgu++; console.log("  " + k.ad.padEnd(20) + x); }
}
console.log(`\n${ISARETLEME.length} bolumde ${bulgu} bulgu`);
```

```
coklu kip:
  calistirilan        aria-expanded           gorunur panel
  (baslangic)         0 0 0                   0
  Baskılar            1 0 0                   1
  Konu başlıkları     1 1 0                   2
  Benzer kayıtlar     1 1 1                   3
  Konu başlıkları     1 0 1                   2

tekli kip:
  calistirilan        aria-expanded           gorunur panel
  (baslangic)         0 0 0                   0
  Baskılar            1 0 0                   1
  Konu başlıkları     0 1 0                   1
  Benzer kayıtlar     0 0 1                   1
  Benzer kayıtlar     0 0 0                   0

degismez taramasi:
  taranan durum: 12, degismez kirilmasi: 0
  tekli kipte ulasilan durum sayisi: 4

yapisal kural denetimi:
  Konu başlıkları     baslik dugmesi bir baslik ogesi icinde degil (div)
  Benzer kayıtlar     aria-controls var olmayan bir kimlige isaret ediyor (panel-benzer-2)
  Benzer kayıtlar     aria-expanded=true ama panel gizli

3 bolumde 3 bulgu
```

## Bulguların Okunması

İki izin karşılaştırılması, iki kipin **durum uzayı** farkını gösteriyor. Çoklu kipte üç
bölüm sekiz duruma ulaşır: her bölüm bağımsız olarak açık ya da kapalıdır. Tekli kipte
ulaşılan durum sayısı dörttür — üç bölüm ya da hiçbiri. Tarama toplamı on iki, ikisinin
toplamıdır.

Tekli kipin izindeki üçüncü satır, kalıbın sık atlanan sonucunu gösteriyor: kullanıcı ikinci
bölümü açtığında birincisi **kendiliğinden kapanıyor**. Ekranda bu, sayfanın kaydığı ve
okunan yerin kaybolduğu anlamına gelir. Kapanma bir duyuru üretmez; kullanıcı yalnız
açtığını duyar. Bu yüzden tekli kip, yalnız bölüm sayısı çok ve içerikler uzun olduğunda
seçilir.

Yapısal denetim üç bulgu üretiyor ve üçü de ekranda görünmez.

**Başlık ögesi eksikliği.** İkinci bölümün açma düğmesi bir `div` içinde. Ekranda hiçbir
fark yoktur; ana hatta ise o bölüm bulunmaz ve başlık listesinden gezinen kullanıcı üç
bölümden yalnız ikisini görür.

**Kopuk denetim başvurusu.** Üçüncü bölümün `aria-controls` değeri var olmayan bir kimliğe
işaret ediyor; bildirim sessizce düşer.

**Bildirim ile görünürlüğün ayrışması.** Aynı bölüm genişletilmiş olarak bildiriliyor ama
paneli gizli. Bu, kalıbın en pahalı kusurudur: kullanıcıya bölümün açık olduğu söylenir,
açıldığında hiçbir içerik bulunmaz ve kullanıcı hatanın kendisinde olduğunu düşünür.

## Klavye Sözleşmesi

| Tuş | Davranış |
|---|---|
| `Tab` | Her başlık düğmesi ayrı bir sekme durağıdır. |
| `Enter` / `Boşluk` | Bölümü açar ya da kapatır. |
| Ok tuşları | İsteğe bağlıdır; kurulursa başlıklar arasında gezinir, bölüm açmaz. |

Sekme kalıbından ayrıldığı nokta buradadır. Sekme şeridi tek bir seçim taşıdığı için dönen
sekme durağı kullanır; akordeonun başlıkları ise bağımsız düğmelerdir ve her biri kendi
durağını tutar. Dönen sekme durağı burada uygulanırsa kullanıcı `Tab` tuşuyla ikinci bölüme
hiç ulaşamaz.

Bir bölüm açıldığında odak **düğmede kalır**. Panele taşınmaz: kullanıcı açtığı bölümü
okumadan bir sonrakini açmak isteyebilir ve odağın kaçması bunu engeller. Panelin içine
girmek `Tab` tuşuyla yapılır.

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

**4.1.2 Ad, Rol, Değer.** Genişleme durumu program yoluyla okunabilmeli ve her değişimde
güncellenmelidir.

**2.5.8 Hedef Boyutu.** Başlık satırının tamamı tıklanabilir alandır; yalnızca ok simgesinin
tıklanabilir olduğu bir gerçekleştirim hem hedefi 24 pikselin altına düşürür hem de
kullanıcının başlık metnine tıklama beklentisini karşılamaz.

**1.4.11 Metin Dışı Kontrast.** Bölümleri birbirinden ayıran çizgi bilgi taşır ve 3:1
ölçüsüne girer.

**2.4.6 Başlıklar ve Etiketler.** Başlık metni bölümün içeriğini tanımlamalıdır; "Ayrıntı"
ya da "Diğer" gibi metinler bu ölçütü karşılamaz.

**2.3.3 Etkileşimle Tetiklenen Hareket.** Açılma hareketine geçiş uygulanıyorsa, hareket
azaltma tercihi bildirildiğinde geçiş kaldırılmalıdır; ölçüt AAA düzeyindedir, ancak uzun
listelerde art arda açılan bölümlerin hareketi rahatsızlık üretir.

## Sık Yapılan Hata

**Durum bildiriminin panele yazılması.** `aria-expanded` özniteliği paneli genişleten
denetime yazılır. Panele yazıldığında düğme durumsuz kalır ve kullanıcı düğmeye
odaklandığında bölümün açık mı kapalı mı olduğunu öğrenemez. Saptaması: `role` değeri düğme
olan her ögede bildirimin bulunup bulunmadığının denetlenmesi.

**Başlık düğmesinin bağlantı olarak kurulması.** Bölüm açmak bir eylemdir ve adres
değiştirmez; bileşen düğmedir.

**Kapalı panelin ağaçta bırakılması.** Panel yalnız sunum katmanında gizlendiğinde ağaçta
kalır; kullanıcı kapalı bölümlerin içeriğini de okur ve durum bildirimiyle çelişir.
Saptaması, denetimin üçüncü kuralıdır.

**Bütün bölümlerin açık başlatılması.** Aşamalı gösterim, sayfayı kısaltmak içindir; hepsi
açık başlayan bir akordeon yalnız fazladan bir tuş katmanı ekler. Karar: sayfa yüklendiğinde
hangi bölümün açık olacağı belirtimde yazılır.

## Özet

- Akordeon ikincil içeriği katlar; zorunlu bilgi, sayfa içinde aranması gereken içerik ve
  çok kısa bölümler katlanmaz.
- Kalıbın yerel karşılığı vardır ve açma davranışını, odaklanabilirliği, tuş sözleşmesini ve
  durum bildirimini birlikte getirir.
- Elle kurulduğunda düğme bir başlık ögesinin içine yazılır; başlık düğmenin içine değil.
  Bu, bölümü ana hatta sokar.
- `aria-expanded` bildirimi paneli genişleten düğmeye yazılır ve görünürlükle her durumda
  örtüşmelidir.
- Akordeonun her başlığı ayrı bir sekme durağıdır; dönen sekme durağı yalnız sekme
  kalıbına aittir.
- Tekli kipte bir bölümün açılması diğerini sessizce kapatır ve durum uzayını sekizden
  dörde indirir; bu davranış yalnız uzun içerikli çok bölümlü listelerde seçilir.

## Sonraki Adım

Buraya kadarki üç kalıpta açılan içerik sayfanın akışı içinde kaldı: panel bir yer kapladı,
altındaki içeriği aşağı itti ve odak kendi başına ilerledi. Katalogun üst çubuğundaki
"Hesabım" denetimi ise farklı davranır — açtığı liste sayfanın **üstünde** durur, altındaki
içeriği örter ve dışına tıklandığında kapanır. Bu, odağın kuşatılmasını ve kapanışta bir
dönüş noktasına götürülmesini gerektiren ilk kalıptır. Sonraki ders menüleri ve açılır
panelleri belirtir; ikisinin ayrımını ve odak tuzağının hangi noktada oluştuğunu ele alır.
