shadcn/ui'de içeriği gizleyip gösteren üç bileşen vardır: aynı alanda birden çok paneli sırayla gösteren Tabs, alt alta dizilmiş başlıkların her birinin altında içerik açan Accordion ve tek bir paneli açıp kapatan Collapsible. Üçü de Radix UI primitifleri üzerine kuruludur ve npx shadcn@latest add tabs, add accordion, add collapsible komutlarıyla eklenir. Hangisini seçeceğiniz, kullanıcının aynı anda kaç paneli görmesi gerektiğine bağlıdır.
Bu üç bileşenin belge sayfaları kısadır; çoğunlukla kurulum ve tek bir kullanım örneği içerir. Bu yüzden yazıda belge örneklerini, depodaki resmî demo dosyalarını ve components/ui altındaki kaynak kodu birlikte okuyarak hangi özelliğin nereden geldiğini gösteriyoruz. Radix tarafındaki ayrıntılı API için her belge sayfası Radix belgesine bağlantı verir. Seri haritası shadcn/ui öğrenme rehberi sayfasında.
Tabs: aynı alanda birden çok panel

Tabs, belgeye göre katmanlı içerik bölümlerinden oluşur ve bu bölümler birer birer gösterilir. Elle kurulumda @radix-ui/react-tabs paketi gerekir; CLI tek komutla halleder. Bileşen dört parçadan oluşur: kök Tabs, sekme düğmelerini tutan TabsList, her sekme için TabsTrigger ve her panel için TabsContent. Tetikleyici ile panel aynı value değeriyle eşleşir; kökteki defaultValue başlangıçta hangi panelin açık olacağını belirler.
npx shadcn@latest add tabsimport { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
export function HesapSekmeleri() {
return (
<Tabs defaultValue="hesap" className="w-[400px]">
<TabsList>
<TabsTrigger value="hesap">Hesap</TabsTrigger>
<TabsTrigger value="sifre">Şifre</TabsTrigger>
</TabsList>
<TabsContent value="hesap">Hesap bilgilerinizi buradan değiştirin.</TabsContent>
<TabsContent value="sifre">Şifrenizi buradan değiştirin.</TabsContent>
</Tabs>
)
}value değerleri görünür metinden bağımsızdır; burada Türkçe karakter içermeyen kısa anahtarlar seçmek, ileride bu değerleri adres çubuğuna ya da duruma yazmak istediğinizde işinizi kolaylaştırır. Belgedeki demo, her panelin içine bir Card koyar: hesap panelinde ad ve kullanıcı adı alanları, şifre panelinde mevcut ve yeni şifre alanları ve her kartın altında bir kaydet düğmesi vardır. Kart yapısı Card, Separator ve Scroll Area yazısında, form alanları Input, Textarea ve Input Group yazısında anlatılıyor.
Kaynakta Tabs nasıl stillenir?
Kaynak kod, durumu Radix'in eklediği data-state özniteliğinden okur. TabsList soluk arka planlı, içeriği kadar genişlikte ve yuvarlatılmış bir kutudur. TabsTrigger etkin olduğunda (data-state=active) arka plan rengini alır ve hafif bir gölge kazanır; koyu temada etkin sekme için ayrı kenarlık ve arka plan tonları tanımlıdır. Devre dışı sekmeler tıklanamaz ve soluk görünür; sekme içine koyduğunuz simgeler, başka bir boyut sınıfı vermediyseniz otomatik olarak küçük boyuta getirilir. Kök Tabs ise dikey bir esnek kutudur ve liste ile panel arasında küçük bir boşluk bırakır.
Bileşenler Radix bileşenlerinin tüm özelliklerini olduğu gibi aktarır, çünkü kaynakta her parça React.ComponentProps<typeof TabsPrimitive.Root> gibi Radix tiplerini kullanır. Belgede gösterilmeyen davranışlar (örneğin durumu dışarıdan yönetmek) için Radix UI Tabs sayfasındaki API'ye bakmanız gerekir.
Sekme listesini tam genişliğe yaymak
Kaynakta TabsList için w-fit, her TabsTrigger için ise flex-1 sınıfı tanımlıdır. Bu ikisinin birleşimi kullanışlı bir sonuç verir: listeye className="w-full" verdiğinizde cn() içindeki tailwind-merge w-fit değerini sizin değerinizle değiştirir ve tetikleyiciler flex-1 sayesinde kalan alanı eşit paylaşır. Böylece kaynak dosyaya dokunmadan, iki ya da üç sekmeyi kartın tüm genişliğine yayabilirsiniz. Daha köklü bir değişiklik, örneğin etkin sekmenin alt çizgiyle gösterilmesi, tabs.tsx dosyasındaki data-[state=active] sınıflarını düzenleyerek yapılır.
<Tabs defaultValue="hesap">
<TabsList className="w-full">
<TabsTrigger value="hesap">Hesap</TabsTrigger>
<TabsTrigger value="sifre">Şifre</TabsTrigger>
<TabsTrigger value="bildirim">Bildirimler</TabsTrigger>
</TabsList>
</Tabs>Accordion: başlık başlık açılan içerik
Accordion, belgede dikey olarak dizilmiş ve her biri bir içerik bölümünü açan etkileşimli başlıklar olarak tanımlanır. Elle kurulumda @radix-ui/react-accordion paketi gerekir. Parçalar Accordion, AccordionItem, AccordionTrigger ve AccordionContent şeklindedir. Her AccordionItem benzersiz bir value alır. Belgedeki kullanım örneğindeki içerik metni, bileşenin WAI-ARIA tasarım desenine uyduğunu söyler.
npx shadcn@latest add accordionimport {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion"
export function SSS() {
return (
<Accordion type="single" collapsible className="w-full" defaultValue="item-1">
<AccordionItem value="item-1">
<AccordionTrigger>Ürün bilgisi</AccordionTrigger>
<AccordionContent>Ürünün özelliklerini burada anlatın.</AccordionContent>
</AccordionItem>
<AccordionItem value="item-2">
<AccordionTrigger>Kargo</AccordionTrigger>
<AccordionContent>Teslimat seçeneklerini burada anlatın.</AccordionContent>
</AccordionItem>
<AccordionItem value="item-3">
<AccordionTrigger>İade</AccordionTrigger>
<AccordionContent>İade koşullarını burada anlatın.</AccordionContent>
</AccordionItem>
</Accordion>
)
}type, collapsible ve defaultValue
type="single" aynı anda yalnızca bir öğenin açık kalmasını sağlar; yeni bir başlığa tıklayınca açık olan kapanır. Bu modda collapsible vermezseniz açık olan öğeyi tekrar tıklayarak kapatamazsınız; belgedeki kullanım örneği ve demo bu yüzden collapsible ekler. Demo ayrıca defaultValue="item-1" ile ilk öğeyi açık başlatır. type="multiple" ise birden çok öğenin aynı anda açık kalmasına izin verir; shadcn belgeleri bu modu React 19 sayfasında, bayrakların ne yaptığını anlatan tek öğelik bir açılır bölüm için kullanır. Depodaki yeni Radix tabanlı örnekler de "Multiple" başlığıyla aynı kullanımı gösterir.
<Accordion type="multiple">
<AccordionItem value="bayraklar">
<AccordionTrigger className="font-medium">
--force ve --legacy-peer-deps ne işe yarar?
</AccordionTrigger>
<AccordionContent>
Bu bölüm, React 19 sayfasındaki örneğin Türkçe karşılığıdır.
</AccordionContent>
</AccordionItem>
</Accordion>Bu bayrakların kendisi React 19 peer dependency hatası yazısının konusudur; burada yalnızca type="multiple" kullanımını göstermek için alındı.
Kaynakta Accordion ve animasyon
Kaynak kodda AccordionTrigger, Radix'in başlık öğesiyle sarılır ve sonuna aşağı bakan bir ok simgesi ekler; öğe açıkken simge 180 derece döner. Tetikleyici üzerine gelince altı çizilir, devre dışıyken soluk görünür. AccordionItem her öğenin altına bir çizgi çeker, son öğede bu çizgiyi kaldırır. AccordionContent ise içeriği iki katmanlı yazar: dıştaki Radix içerik öğesi animate-accordion-down ve animate-accordion-up sınıflarıyla açılıp kapanır, içteki div sizin verdiğiniz className değerini alır. Yani AccordionContent bileşenine verdiğiniz sınıflar animasyonlu kaba değil, içerideki metin kutusuna uygulanır.
Bu ayrımın pratik bir faydası var: belgedeki demo her içerik bölümüne birden çok paragraf koyar ve AccordionContent bileşenine flex flex-col gap-4 text-balance verir. Sınıflar iç kutuya gittiği için paragraflar arasında düzenli boşluk oluşur, dıştaki kabın yükseklik animasyonu ise bundan etkilenmez. İçerik bölümüne liste, bağlantı ya da küçük bir form koymak da aynı şekilde çalışır.
Animasyon tarafında iki belge kaydı önemlidir. Ağustos 2024 tarihli CLI kaydı, bileşenlerin artık kendi bağımlılıklarını taşıyabildiğini ve örnek olarak Accordion'ın kendi Tailwind keyframe tanımlarını getirdiğini, CLI'nin bunları tailwind.config.ts dosyanıza işlediğini anlatır. Tailwind v4 sayfası ise 19 Mart 2025 tarihinde tailwindcss-animate paketinin kullanımdan kaldırılıp yerine tw-animate-css getirildiğini, yeni projelerde bunun varsayılan olarak kurulduğunu söyler. Eski bir projede açılma animasyonu çalışmıyorsa önce bu yükseltme adımlarına bakın; ayrıntı shadcn Tailwind v4 geçişi yazısında.
- @plugin 'tailwindcss-animate';
+ @import "tw-animate-css";Collapsible: tek paneli açıp kapatmak
Collapsible, belgede bir paneli genişletip daraltan etkileşimli bileşen olarak tanımlanır. Elle kurulumda @radix-ui/react-collapsible paketi gerekir. Kaynak kodu üç bileşenin en sadesidir: Collapsible, CollapsibleTrigger ve CollapsibleContent yalnızca Radix parçalarını data-slot özniteliğiyle sarar, hiçbir stil sınıfı eklemez. Görünüm tamamen sizin sınıflarınıza kalır.
npx shadcn@latest add collapsibleBelgedeki demo kontrollü kullanımı gösterir: durum React.useState ile tutulur ve open ile onOpenChange özelliklerine verilir. Tetikleyici asChild ile ghost varyantlı, simge boyutlu bir Button hâline getirilir ve ekran okuyucular için sr-only bir metin taşır. İlk öğe her zaman görünür, kalan öğeler CollapsibleContent içinde gizlenir:
"use client"
import * as React from "react"
import { ChevronsUpDown } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/components/ui/collapsible"
export function DepoListesi() {
const [isOpen, setIsOpen] = React.useState(false)
return (
<Collapsible
open={isOpen}
onOpenChange={setIsOpen}
className="flex w-[350px] flex-col gap-2"
>
<div className="flex items-center justify-between gap-4 px-4">
<h4 className="text-sm font-semibold">Yıldızlanan 3 depo</h4>
<CollapsibleTrigger asChild>
<Button variant="ghost" size="icon" className="size-8">
<ChevronsUpDown />
<span className="sr-only">Aç/kapat</span>
</Button>
</CollapsibleTrigger>
</div>
<div className="rounded-md border px-4 py-2 font-mono text-sm">
@radix-ui/primitives
</div>
<CollapsibleContent className="flex flex-col gap-2">
<div className="rounded-md border px-4 py-2 font-mono text-sm">
@radix-ui/colors
</div>
<div className="rounded-md border px-4 py-2 font-mono text-sm">
@stitches/react
</div>
</CollapsibleContent>
</Collapsible>
)
}Durumu kendiniz tutmanız gerekmiyorsa kontrollü kullanım şart değildir; Sidebar belgesindeki örnekler Collapsible bileşenini defaultOpen ile kontrolsüz kullanır. Collapsible'ın en sık kullanıldığı yerlerden biri de budur: kenar çubuğunda açılır kapanır grup ve alt menüler. Oradaki kalıpta Collapsible bileşenine group/collapsible sınıfı verilir ve ok simgesi group-data-[state=open]/collapsible:rotate-180 gibi bir sınıfla açık duruma göre döndürülür; ayrıntılar Sidebar menü ve grupları yazısında.
Mini örnek: sekmeli yardım sayfasında SSS listesi
Gerçek bir sayfada bu bileşenler çoğu zaman birlikte kullanılır. Aşağıdaki örnekte bir yardım sayfası iki sekmeye ayrılır: "Hesap" ve "Faturalandırma". Her sekmenin içinde, bir diziden üretilen bir Accordion bulunur. Diziden üretme kalıbı, depodaki Radix tabanlı Accordion örneğinin kullandığı yöntemle aynıdır: her öğenin value, trigger ve content alanları vardır ve map ile AccordionItem üretilir.
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
const sorular = {
hesap: [
{ value: "sifre", trigger: "Şifremi nasıl değiştiririm?", content: "Ayarlar sayfasındaki şifre bölümünü kullanın." },
{ value: "eposta", trigger: "E-posta adresimi değiştirebilir miyim?", content: "Evet, hesap ayarlarından değiştirebilirsiniz." },
],
fatura: [
{ value: "fatura-indir", trigger: "Faturamı nereden indiririm?", content: "Faturalar sayfasında listelenir." },
],
}
export function YardimSayfasi() {
return (
<Tabs defaultValue="hesap" className="w-full max-w-lg">
<TabsList>
<TabsTrigger value="hesap">Hesap</TabsTrigger>
<TabsTrigger value="fatura">Faturalandırma</TabsTrigger>
</TabsList>
{(["hesap", "fatura"] as const).map((sekme) => (
<TabsContent key={sekme} value={sekme}>
<Accordion type="single" collapsible>
{sorular[sekme].map((s) => (
<AccordionItem key={s.value} value={s.value}>
<AccordionTrigger>{s.trigger}</AccordionTrigger>
<AccordionContent>{s.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</TabsContent>
))}
</Tabs>
)
}Burada value değerlerini dizi sırasından değil, verinin kendisinden alıyoruz. Bu sayede listeye yeni bir soru eklediğinizde ya da sırayı değiştirdiğinizde hem React anahtarları hem de Accordion değerleri aynı kalır; defaultValue ile belirli bir soruyu açık başlatmak isterseniz onu da kararlı bir adla gösterebilirsiniz. Sekme anahtarları (hesap, fatura) hem TabsTrigger hem TabsContent tarafında aynı diziden geldiği için yazım hatası riski de azalır. Panellerdeki içerik bir form olsaydı, belgedeki Tabs demosunun yaptığı gibi her alana benzersiz bir id verip Label bileşenini htmlFor ile bağlamanız gerekirdi; demo bunun için tabs-demo-name ve tabs-demo-current gibi önekli kimlikler kullanır.
Tabs, Accordion ve Collapsible karşılaştırması

| Özellik | Tabs | Accordion | Collapsible |
|---|---|---|---|
| Aynı anda görünen panel | Bir | type single ise bir, multiple ise birden çok | Tek panel, açık ya da kapalı |
| Başlangıç durumu | defaultValue | defaultValue | defaultOpen veya open |
| Eşleştirme | TabsTrigger ve TabsContent aynı value | Her AccordionItem bir value | Gerekmez |
| Hazır stil | Var (liste, etkin sekme) | Var (çizgi, ok, animasyon) | Yok |
| Elle kurulum paketi | @radix-ui/react-tabs | @radix-ui/react-accordion | @radix-ui/react-collapsible |
| Tipik kullanım | Ayar ekranı, hesap ve şifre panelleri | Sık sorulan sorular, uzun bilgi sayfaları | Daha fazla göster, kenar çubuğu grupları |
Seçimi kolaylaştıran pratik bir soru şudur: kullanıcı panelleri birbirinin alternatifi olarak mı görecek, yoksa alt alta okuyacak mı? Alternatif görünümler, örneğin aynı formun farklı bölümleri, sekmeye uygundur. Alt alta okunacak ve çoğu kapalı kalabilecek bölümler, örneğin sık sorulan sorular, Accordion'a uygundur. Tek bir "daha fazlasını göster" alanı için ise Collapsible yeterlidir ve hiçbir hazır stil dayatmaz. Erişilebilirlik kavramları için WCAG temelleri yazısına bakabilirsiniz.
Sık yapılan hatalar
- Tetikleyici ile panelin value değerini eşleştirmemek:
TabsTrigger value="hesap"için birTabsContent value="hesap"olmalıdır; yazım farkı varsa panel hiç görünmez. - defaultValue vermemek: Tabs'ta başlangıç değeri vermezseniz hangi sekmenin açık olacağını belirlememiş olursunuz; belgedeki örnek her zaman
defaultValuekullanır. - single modda collapsible'ı unutmak: Kullanıcı açık öğeyi kapatmak istediğinde tıklama işe yaramaz; kapatılabilir olsun istiyorsanız
collapsibleekleyin. - AccordionContent sınıflarının nereye gittiğini bilmemek: Verdiğiniz
classNameiçtekidivöğesine uygulanır. Animasyonlu dış kabı değiştirmek istiyorsanızaccordion.tsxdosyasını düzenleyin. - Collapsible'dan stil beklemek: Bileşen hiç sınıf eklemez; kenarlık, boşluk ve ok simgesini kendiniz verirsiniz.
- Accordion öğelerine aynı value değerini vermek: Açık öğeler
valueüzerinden izlenir; belgedeki ve demodaki her öğe ayrı bir değer (item-1,item-2,item-3) taşır. Veriden üretirken değerleri kararlı ve benzersiz bir alandan alın. - Simge düğmesine metin koymamak: Demo, yalnızca simge gösteren tetikleyiciye
sr-onlymetin ekler; bunu atlarsanız düğmenin erişilebilir adı kalmaz.
Sık Sorulan Sorular
Accordion ile Collapsible arasındaki fark nedir?
Accordion birden çok başlık ve içerik çiftini yönetir, aralarındaki ilişkiyi type ile belirler ve hazır stil ile animasyon getirir. Collapsible tek bir paneli açıp kapatır ve stil eklemez. Birkaç bölümlük sık sorulan sorular için Accordion, tek bir gizli alan için Collapsible daha uygundur.
Birden çok Accordion öğesini aynı anda açık tutabilir miyim?
Evet, type="multiple" kullanın. Bu modda her öğe diğerlerinden bağımsız açılıp kapanır.
Sekmeleri dikey yerleştirebilir miyim?
shadcn belgesi dikey sekme örneği vermez. Kök Tabs kaynakta dikey bir esnek kutudur ve sınıflarını ezebilirsiniz; Radix tarafındaki yönlendirme seçenekleri için Radix Tabs API sayfasına bakmanız gerekir.
Seçili sekmeyi adres çubuğunda tutabilir miyim?
shadcn belgesi bunun için bir örnek vermez. Bileşen Radix Tabs özelliklerini olduğu gibi aktardığı için, durumu dışarıdan yönetmenin yolunu Radix Tabs API sayfasında bulursunuz; değeri adres çubuğuna yazıp okumak ise sizin yönlendirme kodunuzun işidir.
Accordion animasyonu neden çalışmıyor?
Bileşen animate-accordion-down ve animate-accordion-up sınıflarına dayanır. Bu sınıfların tanımları projenizin animasyon kurulumundan gelir; Tailwind v4'e geçmiş bir projede tailwindcss-animate yerine tw-animate-css kullanıldığından emin olun.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: shadcn/ui öğrenme rehberi · Sidebar menü ve gruplar · Card, Separator, Scroll Area · Tailwind v4 geçişi · Button varyantları · HTML ARIA nedir