# Design Token Mimarisi: Katmanlar, İsimlendirme ve Temalar

> Design token katmanlarını, role göre isimlendirmeyi ve tek bir değişkenle bütün siteyi değiştirmeyi Tailwind CSS, shadcn/ui ve Primer üzerinden anlattım.

Source: https://omergulcicek.com/blog/design-token-mimarisi

Bir projede aynı gri ton kırk farklı yerde elle yazılmışsa, o renk bir karar değil, bir tesadüftür. Rengi değiştirmek istediğinde kırk yeri tek tek bulman gerekir ve hangisinin butona, hangisinin kenarlığa ait olduğunu bilemezsin. Birini atlarsan site iki farklı gri ile kalır.

Farkı kendin dene: bir renk seç ve iki kartın nasıl değiştiğine bak.

Design token'lar bu sorunu çözüyor: kararlara bir isim verip onları tek bir yerde tutuyor. Değeri orada değiştirdiğinde, o ismi kullanan her yer birlikte değişiyor. Bu yazıda bunun nasıl kurulduğunu **Tailwind CSS**, **shadcn/ui** ve GitHub'ın tasarım sistemi **Primer** üzerinden anlattım.

## Token Nedir?

[Design Tokens Community Group](https://www.designtokens.org/tr/2025.10/) token'ları bir tasarım sisteminin bölünemez parçaları olarak tanımlıyor: renkler, boşluklar, yazı ölçekleri. Kısacası token, **isim verilmiş bir tasarım kararı.** Frontend'de bunu çoğunlukla bir CSS değişkeni olarak görürüz.

Tailwind CSS v4'te bu kararlar `@theme` içinde tanımlanıyor ve her biri hem bir CSS değişkeni hem de bir utility class üretiyor:

```css
@theme {
  --color-mint-500: oklch(0.72 0.11 178);
}
```

Bu tanımdan sonra `bg-mint-500` ve `text-mint-500` kullanılabiliyor. Öndeki `--color-` hangi utility'lerin üretileceğini belirliyor; `--spacing-*` boşluk, `--radius-*` köşe utility'leri üretiyor.

## Üç Katman

Yalnızca değişken kullanmak yetmiyor. Kırk yerde `--color-neutral-900` yazıyorsan, kırk yerde gri yazmaktan pek farkı yok: butonun rengini değiştirmek istediğinde yine hangi `neutral-900`'ün butona ait olduğunu aramak zorundasın. Çözüm token'ları katmanlara ayırmak. [Rangle](https://rangle.io/blog/developing-your-token-structure) ve [GitHub Primer](https://primer.style/product/primitives/token-names/) farklı isimler kullansa da ayrım aynı:

| Katman | Primer'daki adı | Ne anlatır? | shadcn/ui | Primer |
| --- | --- | --- | --- | --- |
| Primitive | Base | Ham değer, anlamı yok | `--color-neutral-900` | `--base-size-16` |
| Semantic | Functional | Sistem genelindeki bir karar | `--primary` | `--fgColor-default` |
| Component | Component/pattern | Tek bir bileşene özel karar | `--sidebar-primary` | `--button-primary-bgColor-rest` |

![Her katman bir alttakine referans verir; ham değer yalnızca en altta durur](https://omergulcicek.com/blog/2026/11-10/token-katmanlari.webp)

Katmanları ayıran şey **referansın tek yöne akması.** Bileşen semantic token'ı kullanır, semantic token primitive'e işaret eder, ham değer yalnızca en altta yazılır. Böylece "butonun rengi" kararı tek bir isimde duruyor: `--primary`.

Gerçek hayatta bu şu demek: butonların rengini griden maviye çevirmek istediğinde kırk dosyayı aramıyorsun. `--primary: var(--color-neutral-900)` satırını `var(--color-blue-600)` yapman yetiyor; `bg-primary` kullanan her bileşen birlikte değişiyor. Yazının başındaki kırk yere dağılmış gri, burada tek bir satıra iniyor. [Primer'ın token rehberi](https://github.com/primer/primitives/blob/main/DESIGN_TOKENS_GUIDE.md) kuralı tek cümleyle koyuyor: ham değer kullanma, yalnızca semantic token kullan.

## Tailwind ve shadcn/ui ile Kurmak

shadcn/ui bu modeli hazır getiriyor. Semantic token'lar `:root`'ta tanımlanıyor, ardından `@theme inline` ile Tailwind'e tanıtılıyor:

```css
:root {
  --primary: oklch(0.205 0 0);
  --primary-foreground: oklch(0.985 0 0);
}

@theme inline {
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
}
```

Böylece `bg-primary` ve `text-primary-foreground` class'ları oluşuyor. [Tailwind dokümantasyonu](https://tailwindcss.com/docs/theme), başka bir değişkene referans veren theme variable'larda `inline` kullanılmasını öneriyor. Token'lar [shadcn/ui](https://ui.shadcn.com/docs/theming)'da **zemin ve üstündeki içerik** çiftleri halinde: `--primary` yüzeyin, `--primary-foreground` üstündeki yazının rengi.

Bileşenler de yalnızca bu class'ları kullanıyor:

```tsx
default: "bg-primary text-primary-foreground hover:bg-primary/90"
```

Button hiçbir yerde bir renk değeri yazmıyor. Renk değiştiğinde bileşen dosyasına dokunmuyorsun.

## Tek Satırla Bütün Siteyi Değiştirmek

Bu sitede vurgu rengi turkuaz ve tek bir token'dan geliyor:

```css
:root {
  --brand: oklch(0.511 0.096 186.391);
  --ring: var(--brand);
}

@theme inline {
  --color-brand: var(--brand);
}
```

Bu değer sitede şu yerlerde kullanılıyor:

- ana sayfadaki çağrı butonu (`bg-brand`),
- menüde açık olan sayfa (`text-brand`),
- link alt çizgileri (`decoration-brand`),
- odak halkaları (`--ring: var(--brand)`),
- metin seçimi (`bg-brand/25`).

Turkuazı başka bir renge çevirmek için `--brand` satırını değiştirmem yetiyor. Bileşenlerin hiçbirine dokunmadan bütün sitenin vurgusu birlikte değişiyor. Yazının başındaki demoda değiştirdiğin token buydu.

## İsimlendirme: Görünüşe Göre Değil, Role Göre

Tek yerden değiştirebilmek için ismin de doğru olması gerekiyor. `--turquoise` ismi, rengi mora çevirdiğin gün yalan söylemeye başlar; `--brand` ise rengin ne işe yaradığını anlatır ve renk değişse de doğru kalır.

Büyük sistemlerde isimler birden fazla parçadan oluşuyor. GitHub'ın tasarım sistemi Primer, isimleri sabit bir sırayla kuruyor: önek, namespace, desen, varyant, özellik, varyant, ölçek. Varyant ya deseni ya da özelliği nitelediği için sırada iki yeri var, ama bir token yalnızca bir varyant taşıyabiliyor. Ölçek ise boyut, kalınlık ve etkileşim durumu gibi sıra bildiren değerler için.

![Primer'ın isim sırası: token yalnızca ihtiyaç duyduğu parçaları taşır, ama hep aynı sırayla](https://omergulcicek.com/blog/2026/11-10/token-ismi.webp)

Sıra sabit olunca isim tahmin edilebiliyor. `button-primary-bgColor-rest`'i bilen biri, hover rengini aramadan `button-primary-bgColor-hover` diye yazabilir.

## Kaç Katman Gerekli?

Üç katman her sistem için şart değil. Rangle erken aşamadaki sistemlerde component token'ları tutmayı öneriyor, çünkü tasarım değişince kod değil yalnızca referans değişiyor. Olgun sistemlerde ise bakım yükünü azaltmak için bu katmanı kaldırmayı öneriyor. Primer üç katmanı da tutuyor; shadcn çoğunlukla iki katmanla yetiniyor ve hover rengi için ayrı token yerine `hover:bg-primary/90` kullanıyor.

Pratik bir ölçüt: bir bileşen semantic token'dan gerçekten farklı bir değere ihtiyaç duyuyorsa component token aç. "Belki lazım olur" diye açılanlar, semantic token'ların kopyası olan bir listeye dönüşür.

## Temalar: İsmi Değil, Değeri Değiştir

Koyu tema da aynı fikrin devamı. Bileşenlere dokunmuyorsun; `.dark` altında aynı isimlere yeni değerler veriyorsun:

```css
.dark {
  --primary: oklch(0.922 0 0);
  --primary-foreground: oklch(0.205 0 0);
}
```

![Koyu temada yalnızca semantic token'ın değeri değişir; bileşenin kullandığı class aynı kalır](https://omergulcicek.com/blog/2026/11-10/token-tema.webp)

Koyu temada primary açık bir renge döndüğü için foreground da koyulaşıyor; çiftler bu yüzden birlikte tanımlanıyor. Primer aynı işi `<html>` üzerindeki `data-color-mode` ve `data-dark-theme` attribute'larıyla yapıyor.

## Özet

- Token, isim verilmiş bir tasarım kararı. Değeri tek bir yerde durur, değiştiğinde onu kullanan her yer değişir.
- Primitive ham değeri, semantic rolü, component tek bir bileşenin kararını tutar. Referans hep aşağı akar.
- İsim görünüşü değil rolü anlatır.
- Tailwind ve shadcn/ui bu yapıyı hazır getiriyor; senin işin ham değer yazmamak.
- Temalarda isimler değil, değerler değişir.

## Kaynaklar

- [Design Tokens Community Group: Technical Reports 2025.10](https://www.designtokens.org/tr/2025.10/)
- [GitHub Primer: Token names](https://primer.style/product/primitives/token-names/)
- [GitHub Primer: Design Tokens Guide](https://github.com/primer/primitives/blob/main/DESIGN_TOKENS_GUIDE.md)
- [shadcn/ui: Theming](https://ui.shadcn.com/docs/theming)
- [Tailwind CSS: Theme variables](https://tailwindcss.com/docs/theme)
- [Rangle: Developing Your Token Structure](https://rangle.io/blog/developing-your-token-structure)
