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

# Sekmeler

Sekme başlıklarıyla panellerin ilişkilendirilmesi, dönen sekme durağının zorunluluğu, kendiliğinden ve elle etkinleştirme kararı ve seçim değişmezinin sınanması.

Kart, içindeki denetimlerin toplamıydı ve kendisi bir davranış taşımıyordu. Kayıt ayrıntısı
sayfası ise farklıdır: künye, mevcut kopyalar ve ödünç geçmişi üç ayrı bölümdür, aynı anda
yalnız biri gösterilir ve hangisinin gösterileceğine kapsayıcının kendisi karar verir.

Bu kalıbın iki gereksinimi vardır ve ikisi de kendiliğinden karşılanmaz. Kullanıcı üç
başlığın var olduğunu ve hangisinin etkin olduğunu bilmelidir; klavyeyle üçü arasında
gezinebilmelidir. Bu ders sekme kalıbını belirtir.

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

Sekme, **eşdeğer ve birbirini dışlayan** içerik bölümlerinin aynı yeri paylaşmasını sağlar.
Üç koşulun tamamı gerekir: bölümler aynı düzeydedir, aynı anda yalnız biri anlamlıdır ve
kullanıcı aralarında sık geçiş yapar.

Koşullar sağlanmıyorsa kalıp yanlıştır. Sıralı okunması gereken bölümler — ödünç alma
formunun üç adımı — sekme değildir; kullanıcı ikinci adıma geçmeden birincisini tamamlamak
zorundadır. Aynı anda okunması gereken bölümler de sekme değildir: künyeyi okurken mevcut
kopya sayısına bakmak gerekiyorsa, ikisi ayrı sekmelere konamaz.

İçerik uzunluğu da bir ölçüttür. Beşten fazla sekme, başlıkların taşmasına ve kaydırmalı bir
başlık şeridine yol açar; o noktada kalıp bir gezinme listesine dönüşmüştür ve sekme olarak
kurulmamalıdır.

## Yerel Öge Önce

Sekme kalıbının yerel karşılığı **yoktur**. Kalıp üç rolle kurulur: sekme şeridi
`role="tablist"`, her başlık `role="tab"`, her bölüm `role="tabpanel"`.

Başlıklar birer düğmedir; `button` ögesinin üzerine rol yazılır. Yerel öge, rol dışındaki
her şeyi getirir: odaklanabilirlik, giriş ve boşluk tuşlarıyla çalıştırılabilirlik, devre
dışı bildirimi.

```html
<div role="tablist" aria-label="Kayıt bölümleri">
  <button role="tab" id="sekme-kunye" aria-selected="true"
          aria-controls="panel-kunye" tabindex="0">Künye</button>
  <button role="tab" id="sekme-kopya" aria-selected="false"
          aria-controls="panel-kopya" tabindex="-1">Mevcut kopyalar</button>
  <button role="tab" id="sekme-gecmis" aria-selected="false"
          aria-controls="panel-gecmis" tabindex="-1">Ödünç geçmişi</button>
</div>

<div role="tabpanel" id="panel-kunye" aria-labelledby="sekme-kunye" tabindex="0">…</div>
<div role="tabpanel" id="panel-kopya" aria-labelledby="sekme-kopya" tabindex="0" hidden>…</div>
<div role="tabpanel" id="panel-gecmis" aria-labelledby="sekme-gecmis" tabindex="0" hidden>…</div>
```

Bağ **iki yönlüdür**: sekme `aria-controls` ile panele, panel `aria-labelledby` ile sekmeye
işaret eder. İkinci yön adın kaynağıdır — panelin erişilebilir adı sekmenin metnidir ve
ayrıca yazılmaz. Şeridin `aria-label` bildirimi de gereklidir; sayfada birden çok sekme
şeridi bulunabildiği için hangisinin hangisi olduğu ayırt edilebilmelidir.

Panellerin `tabindex="0"` taşıması, içinde odaklanabilir öge bulunmayan bir panele
klavyeyle ulaşılabilmesi içindir. Panel bir liste ya da tablo taşıyorsa bu değer gereksizdir;
kullanıcı zaten içeri girer.

## Dönen Sekme Durağı Burada Zorunludur

Sekme şeridinde yalnız bir başlık sekme sırasındadır; kalanların `tabindex` değeri eksi
birdir. Seçim değiştiğinde bu değerler birlikte güncellenir.

Gerekçe sayısaldır. Üç sekmeli bir şeritte düzenin kazancı iki duraktır. Ancak kalıbın
sözleşmesi ok tuşlarını başlıklar arası gezinmeye ayırdığı için, `Tab` tuşunun şerit
içinde ilerlemesi iki gezinme yolunu üst üste bindirir ve kullanıcı hangi tuşun ne
yaptığını öğrenemez. Dönen sekme durağı, `Tab` tuşuna tek bir anlam bırakır: şeritten çık.

## Kendiliğinden mi, Elle mi?

Ok tuşu odağı taşıdığında seçim de taşınsın mı? İki karar da tanımlıdır.

**Kendiliğinden etkinleştirmede** odak hangi başlığa gelirse o panel açılır. Kullanıcı üç
sekmeyi ok tuşuyla gezerken üç paneli de görür; tuş sayısı azdır.

**Elle etkinleştirmede** ok tuşu yalnız odağı taşır, panel giriş ya da boşluk tuşuyla açılır.
Bu iki tuş vuruşu gerektirir.

Karar ölçütü, panel içeriğinin **anında hazır olup olmadığıdır**. Ödünç geçmişi sunucudan
getiriliyorsa, kendiliğinden etkinleştirme kullanıcının gezinirken üç ayrı istek başlatmasına
yol açar; ekran her ok vuruşunda değişir ve ekranı görmeyen kullanıcı için panel içeriği
odak hâlâ şeritteyken değişmiş olur. Panel içeriği belgede hazırsa kendiliğinden
etkinleştirme yeğlenir.

```js
// sekme.test.mjs — sekme kalibinin klavye sozlesmesi ve panel iliskisi
// Kosum: node --test sekme.test.mjs
import { test } from "node:test";
import assert from "node:assert/strict";

const SEKMELER = ["Künye", "Mevcut kopyalar", "Ödünç geçmişi"];

// kip: "kendiliginden" | "elle"
const baslangic = (kip) => ({ kip, secili: 0, odak: { yer: "liste", i: 0 } });

function tus(d, t) {
  const n = SEKMELER.length;
  if (d.odak.yer !== "liste") {
    // Panel icindeyken sekme listesinin tuslari calismaz
    return t === "Shift+Tab" ? { ...d, odak: { yer: "liste", i: d.secili } } : d;
  }
  const i = d.odak.i;
  const git = (y) => ({
    ...d,
    odak: { yer: "liste", i: y },
    secili: d.kip === "kendiliginden" ? y : d.secili,
  });
  if (t === "ArrowRight") return git((i + 1) % n);
  if (t === "ArrowLeft") return git((i + n - 1) % n);
  if (t === "Home") return git(0);
  if (t === "End") return git(n - 1);
  if (t === "Enter" || t === "Space") return { ...d, secili: i };
  if (t === "Tab") return { ...d, odak: { yer: "panel", i: d.secili } };
  return d;
}

const uygula = (d, dizi) => dizi.reduce(tus, d);

// Sekme listesinin kapladigi sekme duragi sayisi (donen sekme duragi)
const listeDuragi = () => 1;

// Isaretlemenin uretecegi oznitelikler
function oznitelikler(d) {
  return SEKMELER.map((ad, i) => ({
    ad,
    role: "tab",
    "aria-selected": d.secili === i,
    "aria-controls": "panel-" + i,
    tabindex: d.odak.yer === "liste" && d.odak.i === i ? 0 : -1,
    panelGizli: d.secili !== i,
  }));
}

test("sekme listesi donen sekme duragiyla tek durak tutar", () => {
  assert.equal(listeDuragi(), 1);
  const oz = oznitelikler(baslangic("elle"));
  assert.equal(oz.filter((o) => o.tabindex === 0).length, 1);
});

test("kendiliginden kipte ok tusu odagi ve secimi birlikte tasir", () => {
  const d = uygula(baslangic("kendiliginden"), ["ArrowRight"]);
  assert.equal(d.odak.i, 1);
  assert.equal(d.secili, 1);
});

test("elle kipte ok tusu yalniz odagi tasir, giris tusu secer", () => {
  const a = uygula(baslangic("elle"), ["ArrowRight", "ArrowRight"]);
  assert.equal(a.odak.i, 2);
  assert.equal(a.secili, 0);
  const b = uygula(a, ["Enter"]);
  assert.equal(b.secili, 2);
});

test("ok tuslari uclarda basa doner", () => {
  const sag = uygula(baslangic("elle"), ["ArrowLeft"]);
  assert.equal(sag.odak.i, 2);
  const sol = uygula(baslangic("elle"), ["ArrowRight", "ArrowRight", "ArrowRight"]);
  assert.equal(sol.odak.i, 0);
});

test("Home ve End ilk ve son sekmeye gider", () => {
  const d = uygula(baslangic("elle"), ["ArrowRight", "Home"]);
  assert.equal(d.odak.i, 0);
  assert.equal(uygula(baslangic("elle"), ["End"]).odak.i, 2);
});

test("Tab sekme listesinden secili panele gecer, panelde ok tusu calismaz", () => {
  const d = uygula(baslangic("elle"), ["ArrowRight", "Enter", "Tab"]);
  assert.deepEqual(d.odak, { yer: "panel", i: 1 });
  const e = uygula(d, ["ArrowRight", "Home"]);
  assert.deepEqual(e.odak, { yer: "panel", i: 1 });
  assert.equal(e.secili, 1);
});

test("her durumda tek sekme secili ve yalniz onun paneli gorunur", () => {
  const TUSLAR = ["ArrowRight", "ArrowLeft", "Home", "End", "Enter", "Tab", "Shift+Tab"];
  const anahtar = (d) => [d.kip, d.secili, d.odak.yer, d.odak.i].join("|");
  let sayi = 0;
  for (const kip of ["kendiliginden", "elle"]) {
    const b = baslangic(kip);
    const gorulen = new Map([[anahtar(b), b]]);
    const kuyruk = [b];
    while (kuyruk.length) {
      const d = kuyruk.shift();
      for (const t of TUSLAR) {
        const y = tus(d, t);
        if (gorulen.has(anahtar(y))) continue;
        gorulen.set(anahtar(y), y);
        kuyruk.push(y);
      }
    }
    for (const d of gorulen.values()) {
      const oz = oznitelikler(d);
      assert.equal(oz.filter((o) => o["aria-selected"]).length, 1, "birden cok secili sekme");
      assert.equal(oz.filter((o) => !o.panelGizli).length, 1, "birden cok gorunur panel");
      const gorunur = oz.find((o) => !o.panelGizli);
      const secili = oz.find((o) => o["aria-selected"]);
      assert.equal(gorunur.ad, secili.ad, "gorunur panel secili sekmeye ait degil");
    }
    sayi += gorulen.size;
  }
  console.log(`  taranan durum sayisi: ${sayi}`);
});
```

```
  taranan durum sayisi: 18
✔ sekme listesi donen sekme duragiyla tek durak tutar (0.35ms)
✔ kendiliginden kipte ok tusu odagi ve secimi birlikte tasir (0.080042ms)
✔ elle kipte ok tusu yalniz odagi tasir, giris tusu secer (0.045292ms)
✔ ok tuslari uclarda basa doner (0.0495ms)
✔ Home ve End ilk ve son sekmeye gider (0.304459ms)
✔ Tab sekme listesinden secili panele gecer, panelde ok tusu calismaz (0.293292ms)
✔ her durumda tek sekme secili ve yalniz onun paneli gorunur (0.408875ms)
ℹ tests 7
ℹ suites 0
ℹ pass 7
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 34.610458
```

Süre değerleri koşumdan koşuma değişir.

Son sınama on sekiz durumun tamamında üç değişmezi doğruluyor: tek sekme seçili, tek panel
görünür ve görünen panel seçili sekmeye ait. Üçüncüsü en çok kırılan koşuldur; seçim
bildirimiyle görünürlük ayrı kod yollarında güncellendiğinde ağaç bir sekmeyi seçili
gösterirken ekran başka bir paneli açık tutabilir.

Altıncı sınama, panelin içinde ok tuşlarının şeridi etkilememesini denetliyor. Bu, tek
karakterli kısayol kuralının bu kalıptaki karşılığıdır: sekme sözleşmesinin tuşları yalnız
şerit odaktayken etkindir. Panelde bir tablo varsa ok tuşları o tabloya aittir.

## Klavye Sözleşmesi

| Tuş | Davranış |
|---|---|
| `Tab` | Odağı şeride getirir; şerit tek duraktır. Şeritteyken seçili panele geçer. |
| `Sağ ok` / `Sol ok` | Odağı komşu sekmeye taşır; uçlarda başa döner. |
| `Home` / `End` | Odağı ilk ve son sekmeye taşır. |
| `Enter` / `Boşluk` | Odaktaki sekmeyi seçer (elle etkinleştirme kipinde). |

Şerit dikey çizildiğinde yukarı ve aşağı ok tuşları da aynı işi görür ve şeride
`aria-orientation="vertical"` yazılır.

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

**4.1.2 Ad, Rol, Değer.** Her sekmenin adı, rolü ve seçili olup olmadığı program yoluyla
okunabilmelidir; `aria-selected` bildirimi seçim her değiştiğinde güncellenir.

**1.4.1 Rengin Tek Taşıyıcı Olmaması.** Etkin sekme yalnız metin rengiyle ayrılamaz; bir
alt çizgi, bir dolgu ya da bir kalınlık farkı ikinci kanaldır.

**1.4.11 Metin Dışı Kontrast.** Etkin sekmeyi gösteren çizgi, komşu yüzeyden en az 3:1 ile
ayrılmalıdır.

**2.4.7 Odak Görünürlüğü.** Odak göstergesi şeridin taşan kenarında kırpılmamalıdır; şerit
yatay kaydırma taşıyorsa odaklanan sekme görünür alana getirilmelidir.

**2.5.8 Hedef Boyutu.** Sekme başlıkları 24 piksel ölçüsüne girer; dar şeritlerde başlıklar
arası aralık istisnayı sağlayacak kadar açık olmalıdır.

**1.4.10 Yeniden Akış.** Dar ekranda şerit yatay kaydırmaya bırakılırsa, kaydırma
kullanıcının fark edebileceği bir gösterge taşımalıdır; taşmayan bir şerit için başlıkların
alt alta dizilmesi de bir çözümdür.

## Sık Yapılan Hata

**Panelin gizlenmeden bırakılması.** Seçili olmayan paneller yalnız sunum katmanında
gizlendiğinde — ekran dışına taşınarak ya da saydamlaştırılarak — ağaçta durmayı sürdürürler.
Kullanıcı üç panelin içeriğini de arka arkaya okur. Saptaması: görünür panel sayısıyla
seçili sekme sayısının karşılaştırılması.

**Sekmelerin bağlantı olarak kurulması.** Sekme bir adres değiştirmiyorsa düğmedir. Adres
değiştiriyorsa — her bölümün paylaşılabilir bir adresi varsa — kalıp sekme değil, gezinme
listesidir ve `aria-current` ile bildirilir.

**Şeridin adsız bırakılması.** Saptaması bir varlık kuralıdır: `role="tablist"` taşıyan her
ögenin bir adı bulunmalıdır.

**İki gezinme yolunun üst üste binmesi.** `Tab` tuşunun şerit içinde ilerlediği bir
gerçekleştirimde ok tuşları da aynı işi yapar. Saptaması, şeritteki `tabindex` değerlerinin
sayılmasıdır: sıfır değerini taşıyan öge sayısı birden büyükse dönen sekme durağı
kurulmamıştır.

## Özet

- Sekme kalıbı, eşdeğer ve birbirini dışlayan bölümler için kullanılır; sıralı ya da aynı
  anda okunması gereken bölümlerde kullanılmaz.
- Kalıbın yerel karşılığı yoktur; şerit, başlık ve panel rolleri yazılır ve bağ iki
  yönlüdür — panelin adı sekmeden gelir.
- Dönen sekme durağı zorunludur: `Tab` tuşuna tek bir anlam bırakır, ok tuşlarını şerit
  içindeki gezinmeye ayırır.
- Kendiliğinden etkinleştirme panel içeriği belgede hazırsa yeğlenir; sunucudan getirilen
  içerikte elle etkinleştirme seçilir.
- Üç değişmez her durumda korunmalıdır: tek sekme seçili, tek panel görünür ve görünen panel
  seçili sekmeye ait.
- Sekme sözleşmesinin tuşları yalnız şerit odaktayken etkindir; panel içindeki tablo ya da
  liste kendi ok tuşu davranışını sürdürür.

## Sonraki Adım

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ı okuyabilir. Bu, aynı gruplama sorununun kısıtsız çözümüdür ve tek bir durum
bildirimine dayanır: bölüm şu anda genişletilmiş mi? Sonraki ders akordeonu belirtir ve o
tek bildirimin güncellenmemesinin neden en sık üretilen kusur olduğunu gösterir.
