shadcn/ui Sidebar, uygulamanızın yan menüsünü tek parça bir kutu olarak değil, birbirine takılan küçük parçalar hâlinde verir. Kurmak için npx shadcn@latest add sidebar komutunu çalıştırırsınız; ardından uygulamanın kökünü SidebarProvider ile sarar, içine kendi AppSidebar bileşeninizi ve açıp kapatan SidebarTrigger düğmesini koyarsınız. Genişlik, klavye kısayolu ve çerezle kalıcı açık/kapalı durumu doğrudan components/ui/sidebar.tsx dosyasındaki sabitlerle ayarlanır.

Bu yazı, Sidebar ailesinin iskeletini anlatıyor: kurulum, parçaların yerleşimi, SidebarProvider ve Sidebar bileşenlerinin özellikleri, useSidebar kancası ve ilk çalışan menü. Menü öğeleri, gruplar, alt menüler, rozetler, iskelet yükleme durumu, kontrollü kullanım ve tema değişkenleri ise devam yazısı Sidebar menü ve grupları içinde. Serinin tamamı için shadcn/ui öğrenme rehberi sayfasına bakabilirsiniz.

Kurulum: CLI ve CSS renkleri

CLI ile kurulum tek komuttur. Komut components/ui/sidebar.tsx dosyasını projenize ekler. Depodaki kayıt tanımına göre Sidebar; button, separator, sheet, tooltip, input, skeleton bileşenlerine ve use-mobile kancasına bağımlıdır, npm tarafında da @radix-ui/react-slot, class-variance-authority ve lucide-react paketlerini ister. CLI bu kayıt bağımlılıklarını da birlikte çözer; CLI'nin genel çalışması için shadcn CLI komutları yazısına bakın.

bash
npx shadcn@latest add sidebar

İkinci adım renkler. Belgeye göre komut, kenar çubuğuna özel CSS değişkenlerini sizin için eklemelidir; eklemediyse aşağıdaki bloğu app/globals.css dosyanıza kendiniz kopyalarsınız. Değerler oklch biçimindedir ve hem açık tema (:root) hem de koyu tema (.dark) için tanımlanır.

css
@layer base {
  :root {
    --sidebar: oklch(0.985 0 0);
    --sidebar-foreground: oklch(0.145 0 0);
    --sidebar-primary: oklch(0.205 0 0);
    --sidebar-primary-foreground: oklch(0.985 0 0);
    --sidebar-accent: oklch(0.97 0 0);
    --sidebar-accent-foreground: oklch(0.205 0 0);
    --sidebar-border: oklch(0.922 0 0);
    --sidebar-ring: oklch(0.708 0 0);
  }

  .dark {
    --sidebar: oklch(0.205 0 0);
    --sidebar-foreground: oklch(0.985 0 0);
    --sidebar-primary: oklch(0.488 0.243 264.376);
    --sidebar-primary-foreground: oklch(0.985 0 0);
    --sidebar-accent: oklch(0.269 0 0);
    --sidebar-accent-foreground: oklch(0.985 0 0);
    --sidebar-border: oklch(1 0 0 / 10%);
    --sidebar-ring: oklch(0.439 0 0);
  }
}

Elle kurulumda ise belge, bileşen kaynağını components/ui/sidebar.tsx olarak kopyalamanızı, içe aktarma yollarını projenize göre düzeltmenizi ve aynı CSS değişkenlerini eklemenizi ister. Bu değişkenlerin uygulamanın geri kalanından neden ayrı tutulduğu devam yazısının tema bölümünde, genel tema sistemi ise shadcn tema ve CSS değişkenleri yazısında anlatılıyor.

İlk sidebar: menülü, açılıp kapanan bir kenar çubuğu

Belgedeki "Your First Sidebar" adımları, yukarıdaki düzen dosyasını koruyup AppSidebar içine bir SidebarGroup ve onun içine bir SidebarMenu koyar. Aşağıdaki örnek belgedekiyle aynı yapıyı ve aynı içe aktarmaları kullanır; yalnızca etiketler Türkçeleştirildi. Simgeler lucide-react paketinden gelir.

typescript
import { Calendar, Home, Inbox, Search, Settings } from "lucide-react"

import {
  Sidebar,
  SidebarContent,
  SidebarGroup,
  SidebarGroupContent,
  SidebarGroupLabel,
  SidebarMenu,
  SidebarMenuButton,
  SidebarMenuItem,
} from "@/components/ui/sidebar"

// Menü öğeleri.
const items = [
  { title: "Ana sayfa", url: "#", icon: Home },
  { title: "Gelen kutusu", url: "#", icon: Inbox },
  { title: "Takvim", url: "#", icon: Calendar },
  { title: "Arama", url: "#", icon: Search },
  { title: "Ayarlar", url: "#", icon: Settings },
]

export function AppSidebar() {
  return (
    <Sidebar>
      <SidebarContent>
        <SidebarGroup>
          <SidebarGroupLabel>Uygulama</SidebarGroupLabel>
          <SidebarGroupContent>
            <SidebarMenu>
              {items.map((item) => (
                <SidebarMenuItem key={item.title}>
                  <SidebarMenuButton asChild>
                    <a href={item.url}>
                      <item.icon />
                      <span>{item.title}</span>
                    </a>
                  </SidebarMenuButton>
                </SidebarMenuItem>
              ))}
            </SidebarMenu>
          </SidebarGroupContent>
        </SidebarGroup>
      </SidebarContent>
    </Sidebar>
  )
}

Burada dikkat edilecek üç ayrıntı var. Birincisi, SidebarMenuButton varsayılan olarak bir button üretir; asChild verdiğinizde stilini içindeki a etiketine aktarır, böylece öğe gerçek bir bağlantı olur. İkincisi, etiket metni bir span içine konur; kaynaktaki stil son span öğesini kısaltarak taşmayı engeller. Üçüncüsü, SidebarMenuItem bir li, SidebarMenu bir ul olarak render edilir; yani liste anlamı korunur. asChild ve Slot mantığının ayrıntısı bileşen özelleştirme ve cva yazısında.

SidebarProvider: durum, genişlik, kısayol ve çerez

SidebarProvider kenar çubuğu bağlamını sağlayan bileşendir ve belge uygulamanızı her zaman bununla sarmanızı söyler. Belgede listelenen özellikleri üç tanedir:

ÖzellikTipAçıklama
defaultOpenbooleanKenar çubuğunun başlangıçtaki açık durumu (kontrolsüz kullanım)
openbooleanAçık durum (kontrollü kullanım)
onOpenChange(open: boolean) => voidAçık durumu değiştiren geri çağırma (kontrollü kullanım)

Kaynak koda göre defaultOpen verilmezse true kabul edilir, yani kenar çubuğu açık başlar. Sağlayıcı ayrıca içerdiği her şeyi TooltipProvider ile sarar ve data-slot="sidebar-wrapper" taşıyan, en az ekran yüksekliğinde bir div üretir. open ve onOpenChange ile durumu dışarıdan yönetmek, devam yazısındaki kontrollü kenar çubuğu bölümünde anlatılıyor.

Genişlik

Uygulamada tek bir kenar çubuğu varsa genişliği sidebar.tsx içindeki iki sabitten değiştirirsiniz. Kaynakta bunların yanında, simgelere daralmış hâlin genişliği için SIDEBAR_WIDTH_ICON sabiti de bulunur ve değeri 3rem olarak tanımlıdır.

typescript
const SIDEBAR_WIDTH = "16rem"
const SIDEBAR_WIDTH_MOBILE = "18rem"

Birden fazla kenar çubuğu kullanıyorsanız sabitleri değiştirmek hepsini etkiler. Belge bu durumda SidebarProvider üzerinde style özelliğiyle --sidebar-width ve --sidebar-width-mobile CSS değişkenlerini vermenizi önerir. Belgeye göre bu yöntem yalnızca genişliği değil, ana içerikle arasındaki yerleşim boşluğunu da ayarlar.

typescript
<SidebarProvider
  style={{
    "--sidebar-width": "20rem",
    "--sidebar-width-mobile": "20rem",
  }}
>
  <Sidebar />
</SidebarProvider>

Klavye kısayolu

Kenar çubuğu Mac'te cmd+b, Windows'ta ctrl+b ile açılıp kapanır. Harf SIDEBAR_KEYBOARD_SHORTCUT sabitinde durur. Kaynaktaki dinleyici, basılan tuş bu harfe eşitse ve aynı anda metaKey ya da ctrlKey basılıysa tarayıcının varsayılan davranışını durdurup toggleSidebar() çağırır. Harfi değiştirmek için sabiti düzenlemeniz yeterlidir:

typescript
const SIDEBAR_KEYBOARD_SHORTCUT = "b"

Çerezle kalıcı durum

SidebarProvider, açık/kapalı durumunu sayfa yenilemeleri ve sunucu tarafı render arasında korumak için çerez kullanır. Durum her değiştiğinde varsayılan adı sidebar_state olan bir çereze güncel değer yazılır. Kaynakta çerez path=/ ile ve SIDEBAR_COOKIE_MAX_AGE süresiyle yazılır; bu sabit 60 * 60 * 24 * 7 saniye, yani yedi gün olarak tanımlıdır. Next.js'te bu çerezi sunucuda okuyup defaultOpen olarak vermek için belge şu düzeni gösterir:

typescript
import { cookies } from "next/headers"

import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"
import { AppSidebar } from "@/components/app-sidebar"

export async function Layout({ children }: { children: React.ReactNode }) {
  const cookieStore = await cookies()
  const defaultOpen = cookieStore.get("sidebar_state")?.value === "true"

  return (
    <SidebarProvider defaultOpen={defaultOpen}>
      <AppSidebar />
      <main>
        <SidebarTrigger />
        {children}
      </main>
    </SidebarProvider>
  )
}

Bu örnekteki karşılaştırmayı dikkatle okuyun: çerez hiç yoksa ?.value sonucu undefined olur ve ifade false döner. Yani ziyaretçi kenar çubuğuna hiç dokunmadıysa ilk açılışta kenar çubuğu kapalı gelir. İlk ziyarette açık başlamasını istiyorsanız ifadeyi çerezin yokluğunu da hesaba katacak şekilde yazmanız gerekir. Çerezin adını değiştirmek için SIDEBAR_COOKIE_NAME sabitini düzenlersiniz. App Router'daki düzen dosyaları ve sunucu bileşenleri için Next.js App Router yazısına bakabilirsiniz.

typescript
const SIDEBAR_COOKIE_NAME = "sidebar_state"

useSidebar kancası

Kenar çubuğunu kendi kodunuzdan kontrol etmek için useSidebar kancasını kullanırsınız. Kanca belgeye göre şu değerleri döndürür:

DeğerTipAçıklama
stateexpanded veya collapsedKenar çubuğunun güncel durumu
openbooleanMasaüstünde açık mı
setOpen(open: boolean) => voidMasaüstü açık durumunu ayarlar
openMobilebooleanMobilde açık mı
setOpenMobile(open: boolean) => voidMobil açık durumunu ayarlar
isMobilebooleanMobil görünümde mi
toggleSidebar() => voidMasaüstünde ve mobilde aç/kapat

Masaüstü ve mobil durumlarının ayrı tutulması önemli bir ayrıntıdır: open masaüstündeki genişlemiş/daralmış hâli, openMobile ise Sheet içinde açılan mobil paneli temsil eder. Kaynaktaki toggleSidebar hangi ekranda olduğunuza bakıp doğru olanı değiştirir; kendi düğmenizi yazarken genellikle bunu kullanmak en güvenli yoldur. Belgedeki özel tetikleyici örneği tam olarak bunu yapar:

typescript
import { useSidebar } from "@/components/ui/sidebar"

export function CustomTrigger() {
  const { toggleSidebar } = useSidebar()

  return <button onClick={toggleSidebar}>Kenar çubuğunu aç/kapat</button>
}

Hazır SidebarTrigger ise kaynakta ghost varyantlı, icon boyutlu bir Button olarak tanımlıdır, içinde panel simgesi ve ekran okuyucular için gizli "Toggle Sidebar" metni bulunur. Ona onClick verirseniz önce sizin işleviniz, ardından toggleSidebar() çalışır. Buton varyantları için Button varyantları yazısına bakabilirsiniz.

Sık yapılan hatalar

  • Sağlayıcı dışında kullanmak: useSidebar, SidebarTrigger, Sidebar ve menü düğmeleri bağlama ihtiyaç duyar. SidebarProvider dışında kullanıldıklarında kaynaktaki kanca useSidebar must be used within a SidebarProvider. hatasını fırlatır. Bu mesaj belgede, Ekim 2024'te düzeltilen bir yazım hatasının sonucu olarak da geçer.
  • inset varyantında SidebarInset'i unutmak: Belge bu varyantta ana içeriğin SidebarInset ile sarılmasını açıkça ister; aksi hâlde içerik beklenen kart görünümünü almaz.
  • CSS değişkenlerini eksik bırakmak: CLI renkleri eklemediyse --sidebar ve diğer değişkenler tanımsız kalır. Kurulum bölümündeki bloğu globals.css dosyasına ekleyin.
  • Çerez karşılaştırmasını yanlış okumak: Belgedeki === "true" ifadesi çerez yokken false verir; ilk ziyaret davranışını bilinçli seçin.
  • Kancayı sunucu bileşeninde çağırmak: sidebar.tsx dosyası "use client" ile başlar, ama useSidebar çağıran kendi bileşeniniz de istemci bileşeni olmalıdır. Next.js'te o dosyanın başına "use client" ekleyin.
  • Birden çok kenar çubuğunda sabitleri değiştirmek: SIDEBAR_WIDTH tüm kenar çubuklarını etkiler; her biri için farklı genişlik istiyorsanız style ile CSS değişkeni verin.

Sık Sorulan Sorular

Kenar çubuğunu sağ tarafa alabilir miyim?

Evet. Sidebar bileşenine side="right" verin. Kaynakta bu değer hem masaüstü yerleşimini hem de mobilde açılan Sheet panelinin yönünü belirler.

Simgelere daralan kenar çubuğu nasıl yapılır?

collapsible="icon" kullanın. Daraldığında genişlik --sidebar-width-icon değişkenine iner. Daralmış hâlde hangi parçaların gizlendiği ve menü düğmelerine ipucu (tooltip) eklemek, Sidebar menü yazısında anlatılıyor.

Mobilde kenar çubuğu neden çekmece gibi açılıyor?

Çünkü kaynak, mobil eşiğin altında kenar çubuğunu Sheet içinde render eder ve durumu openMobile ile ayrı tutar. Bunu istemiyorsanız collapsible="none" ile sabit bir kenar çubuğu kullanabilir ya da kodu kendi ihtiyacınıza göre düzenleyebilirsiniz.

Sidebar hangi framework ile çalışır?

Sürüm geçmişi Next.js, Remix, Vite ve Laravel'i sayar. Çerezle kalıcı durumun sunucuda okunması için belge yalnızca Next.js örneği verir; diğer ortamlarda çerezi kendi sunucu kodunuzla okumanız gerekir. Kurulum adımları için Next.js kurulumu ve Vite kurulumu yazılarına bakın.

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ı · Sheet ve Drawer · Navigation Menu, Breadcrumb ve Pagination · shadcn blocks · Next.js App Router