shadcn/ui'da açılır pencere için iki bileşen vardır: Dialog, sayfanın üstüne açılan ve alttaki içeriği etkileşime kapatan genel amaçlı bir penceredir; AlertDialog ise kullanıcıyı önemli bir içerikle durduran ve ondan mutlaka bir yanıt bekleyen onay penceresidir. İkisi de Radix UI ilkelleri üzerine kurulur, npx shadcn@latest add dialog ve npx shadcn@latest add alert-dialog komutlarıyla projeye eklenir. Profil düzenleme, paylaşım bağlantısı ya da form gibi içerikler için Dialog, "hesabınızı silmek istediğinize emin misiniz?" gibi geri dönüşü olmayan işlemler için Alert Dialog seçilir.
Bu yazıda iki bileşenin parçalarını, depodaki kaynak kodun varsayılanlarını, form içeren pencereyi, pencereyi kodla açıp kapatmayı ve bir menü öğesinden pencere açarken belgenin özellikle vurguladığı ayrıntıyı ele alıyoruz. Kenardan kayan paneller için Sheet ve Drawer, komut paleti için Command yazılarına, serinin tamamı için shadcn/ui öğrenme rehberi sayfasına bakabilirsiniz.
Dialog nedir, neye dayanır?

Belge Dialog'u, ana pencerenin ya da başka bir pencerenin üzerine bindirilen ve altındaki içeriği etkisiz (inert) bırakan bir pencere olarak tanımlar. Bileşen Radix UI: Dialog ilkelinin üstüne yazılmıştır; davranışın büyük kısmı Radix tarafındadır. shadcn/ui bu ilkellere görünüm, animasyon ve küçük kolaylıklar ekler. Radix'in iç işleyişi bu yazının konusu değil; ayrıntılı API için belgede bağlantısı verilen Radix sayfasına bakabilirsiniz.
CLI ile kurulum components/ui/dialog.tsx dosyasını oluşturur ve @radix-ui/react-dialog paketini yükler. Elle kurmak isterseniz aynı paketi kendiniz yükleyip kaynak kodu kopyalar, import yollarını düzeltirsiniz. Dosyanın ilk satırı "use client" olduğu için Next.js App Router içinde istemci bileşeni olarak çalışır.
npx shadcn@latest add dialog
npm install @radix-ui/react-dialogİlk satır CLI ile kurulumdur; ikinci satır yalnızca elle kurulumda gereken bağımlılıktır. Haziran 2025 değişiklik kaydı, npx shadcn@latest migrate radix komutuyla ayrı @radix-ui/react-* paketlerinden tek radix-ui paketine geçilebildiğini de anlatır; komut ui klasöründeki import satırlarını günceller ve radix-ui paketini bağımlılık olarak kurar. Ayrıntı CLI komutları yazısında.
Parçalar ve kaynak koddaki varsayılanlar
Dialog tek bir bileşen değil, birlikte kullanılan küçük parçalardan oluşur. Her parça bir data-slot özniteliği taşır; örneğin içerik kutusu data-slot="dialog-content" ile işaretlenir. Bu öznitelikler, üst bileşenlerden belirli bir parçayı seçip stil vermenizi kolaylaştırır.
| Parça | Görevi |
|---|---|
| Dialog | Kök bileşen; açık/kapalı durumunu tutar |
| DialogTrigger | Pencereyi açan öğe; asChild ile kendi butonunuzu verirsiniz |
| DialogContent | Portal ve karartma katmanıyla birlikte ortalanmış içerik kutusu |
| DialogHeader / DialogFooter | Başlık alanı ve düğme alanı için yerleşim kutuları |
| DialogTitle / DialogDescription | Pencerenin başlığı ve açıklaması |
| DialogClose | Pencereyi kapatan öğe; iptal düğmesi için kullanılır |
| DialogOverlay / DialogPortal | Karartma katmanı ve portal; DialogContent bunları zaten içerir |
Kaynak kodda DialogContent kendi içinde önce bir portal, sonra yarı saydam siyah bir karartma katmanı (bg-black/50) çizer. İçerik kutusu ekranın ortasına sabitlenir, küçük ekranlarda kenarlardan 1rem boşluk bırakacak genişliğe sınırlanır ve sm kırılma noktasından itibaren en fazla max-w-lg genişliğinde olur. Açılış ve kapanışta solma ve hafif büyüme animasyonu uygulanır.
DialogContent bileşenine shadcn/ui'ın eklediği tek özel prop showCloseButton'dır ve varsayılan değeri true'dur. Açık olduğunda sağ üst köşeye çarpı simgeli bir kapatma düğmesi eklenir; düğmenin içinde ekran okuyucular için yalnızca görsel olarak gizlenmiş "Close" metni bulunur. Kendi kapatma düğmenizi kullanacaksanız showCloseButton={false} verebilirsiniz. DialogHeader küçük ekranda metni ortalar, sm ve üstünde sola yaslar. DialogFooter ise küçük ekranda düğmeleri ters sırada alt alta dizer, geniş ekranda yan yana ve sağa yaslı gösterir.
Animasyonlar da öznitelik tabanlıdır. Radix, açık ya da kapalı olmasına göre içerik ve karartma katmanına data-state="open" veya data-state="closed" değerini yazar; kaynak koddaki data-[state=open]:animate-in, data-[state=closed]:fade-out-0 ve data-[state=open]:zoom-in-95 gibi sınıflar bu değere göre devreye girer. Animasyon süresi duration-200 sınıfıyla verilir. Pencerenin açılış efektini değiştirmek istediğinizde dosyada aramanız gereken yer bu sınıflardır. Animasyon sınıflarının hangi paketten geldiği ve eski tailwindcss-animate eklentisinin yerini neyin aldığı Tailwind v4 geçişi yazısında anlatılıyor.
Temel kullanım
Belgedeki en kısa örnek, bir tetikleyici ile başlık ve açıklamadan oluşan bir içerik kutusudur. Gerçek projelerde tetikleyiciye genellikle asChild ile kendi Button bileşeninizi verirsiniz; böylece Radix ayrı bir düğme üretmez, davranışı sizin butonunuza aktarır.
import { Button } from "@/components/ui/button"
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
export function BilgiPenceresi() {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Ayrıntıları göster</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Sipariş ayrıntıları</DialogTitle>
<DialogDescription>
Siparişinizin durumu ve teslimat bilgileri burada yer alır.
</DialogDescription>
</DialogHeader>
</DialogContent>
</Dialog>
)
}Bu kod çerçeveli bir buton çizer; butona basıldığında ekran kararır ve ortada başlık ile açıklama içeren bir kutu açılır. Kutunun sağ üstünde varsayılan kapatma düğmesi bulunur. Button bileşeninin varyantları için Button varyantları yazısına bakın.
Form içeren dialog
Belgenin ana örneği bir profil düzenleme penceresidir. Pencerede iki alan, bir iptal ve bir kaydet düğmesi vardır. İptal düğmesi DialogClose asChild ile sarılır, böylece tıklandığında pencereyi kapatır; kaydet düğmesi ise type="submit" özellikli sıradan bir butondur. Örnekte form öğesi hem tetikleyiciyi hem içeriği sarar. Genişlik className="sm:max-w-[425px]" ile varsayılandan biraz daraltılır.
<Dialog>
<form>
<DialogTrigger asChild>
<Button variant="outline">Profili düzenle</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Profili düzenle</DialogTitle>
<DialogDescription>
Bilgilerinizi değiştirin, bitince kaydet düğmesine basın.
</DialogDescription>
</DialogHeader>
<div className="grid gap-4">
<div className="grid gap-3">
<Label htmlFor="name-1">Ad</Label>
<Input id="name-1" name="name" defaultValue="Ayşe Yılmaz" />
</div>
<div className="grid gap-3">
<Label htmlFor="username-1">Kullanıcı adı</Label>
<Input id="username-1" name="username" defaultValue="@ayse" />
</div>
</div>
<DialogFooter>
<DialogClose asChild>
<Button variant="outline">İptal</Button>
</DialogClose>
<Button type="submit">Kaydet</Button>
</DialogFooter>
</DialogContent>
</form>
</Dialog>Bu örnekte Label ve Input bileşenleri de kullanıldığı için onları ayrıca eklemeniz gerekir; ayrıntılar Input, Textarea ve Input Group yazısında. Gerçek bir uygulamada form durumunu ve doğrulamayı React Hook Form ve Zod ya da Next.js Server Actions ile yönetebilirsiniz; alan düzeni için Field bileşeni de kullanılabilir.
Özel kapatma düğmesi

Belgedeki ikinci örnek bir paylaşım penceresidir: salt okunur bir metin kutusunda bağlantı gösterilir, alt kısımda ise secondary varyantlı bir "Kapat" düğmesi bulunur. Bu düğme yine DialogClose asChild ile sarılır ve type="button" özelliği taşır; HTML'de bu tip bir düğme formu göndermez. Alt alanı sola yaslamak için DialogFooter bileşenine sm:justify-start sınıfı verilir.
<DialogFooter className="sm:justify-start">
<DialogClose asChild>
<Button type="button" variant="secondary">
Kapat
</Button>
</DialogClose>
</DialogFooter>Pencereyi kodla açmak ve kapatmak
Tetikleyiciye tıklamak dışında bir yoldan, örneğin bir işlem bittikten sonra pencereyi kapatmak ya da bir menü öğesinden açmak istediğinizde, açık durumunu kendiniz tutarsınız. Kök bileşen open ve onOpenChange prop'larını kabul eder; shadcn/ui örnekleri, örneğin Dropdown Menu sayfasındaki dialog örneği ve Drawer sayfasındaki responsive örnek, bu kalıbı kullanır. Durumu onOpenChange ile bağladığınızda bileşen kapanmak istediğinde değişkeniniz de güncellenir.
"use client"
import * as React from "react"
export function KontrolluDialog() {
const [open, setOpen] = React.useState(false)
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button variant="outline">Profili düzenle</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Profili düzenle</DialogTitle>
<DialogDescription>Değişiklikleri kaydedin.</DialogDescription>
</DialogHeader>
<Button onClick={() => setOpen(false)}>Tamam</Button>
</DialogContent>
</Dialog>
)
}Bu örnekte import satırlarının geri kalanı önceki örnekle aynıdır. "Tamam" düğmesi DialogClose kullanmadan, durumu doğrudan false yaparak pencereyi kapatır. Aynı yöntemle bir sunucu isteği tamamlandıktan sonra pencereyi kapatabilirsiniz.
Belgedeki tanımın bir ayrıntısı da dikkat çekicidir: Dialog yalnızca ana pencerenin değil, başka bir dialog penceresinin üzerine de açılabilir. Örneğin bir ayarlar penceresinin içindeki "hesabı kapat" düğmesi, üstüne ikinci bir onay penceresi açabilir. Bu durumda her pencere kendi kök bileşenine ve kendi açık durumuna sahip olur. Yine de kullanıcıyı katman katman pencerelerle yormamak için bu yapıyı gerçekten gereken yerlerle sınırlamak iyi bir tasarım kararıdır.
Alert Dialog: yanıt bekleyen onay penceresi
Belge Alert Dialog'u kullanıcıyı önemli bir içerikle kesen ve bir yanıt bekleyen modal pencere olarak tanımlar. Bileşen Radix UI: Alert Dialog ilkeline dayanır; kurulumda @radix-ui/react-alert-dialog paketi yüklenir ve depodaki kayıt tanımına göre button bileşeni de bağımlılık olarak gelir, çünkü düğmeler buttonVariants ile biçimlenir.
npx shadcn@latest add alert-dialogParçaların adları Dialog'a benzer, ama iki yeni parça vardır: AlertDialogAction onay düğmesidir ve varsayılan buton stilini alır; AlertDialogCancel iptal düğmesidir ve outline varyantıyla çizilir. Kaynak koddaki önemli bir fark, AlertDialogContent bileşeninde köşedeki çarpı düğmesinin bulunmamasıdır. Kullanıcıya sunulan kapatma yolu iki düğmedir; bu, bileşenin "yanıt bekler" tanımıyla uyumludur.
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui/button"
export function HesabiSil() {
return (
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="outline">Hesabı sil</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Emin misiniz?</AlertDialogTitle>
<AlertDialogDescription>
Bu işlem geri alınamaz. Hesabınız ve verileriniz kalıcı olarak silinir.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Vazgeç</AlertDialogCancel>
<AlertDialogAction>Devam et</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)
}Onay düğmesinin görünümünü değiştirmek isterseniz AlertDialogAction bileşenine className ile kendi sınıfınızı verebilirsiniz; kaynakta sınıflar cn(buttonVariants(), className) biçiminde birleştirildiği için sizin verdiğiniz sınıf sonda gelir ve çakışan sınıfları ezer. Bu birleştirmenin nasıl çalıştığını cn() fonksiyonu yazısında bulabilirsiniz.
Gerçek bir silme akışında asıl işi AlertDialogAction düğmesinin onClick olayına bağlarsınız; bileşen bir Radix düğmesini sardığı ve kalan prop'ları ona aktardığı için sıradan düğme olaylarını kabul eder. İşlemden sonra kullanıcıya kısa bir bildirim göstermek isterseniz Sonner ile toast bildirimleri yazısındaki toast() çağrısını kullanabilirsiniz. Alert Dialog'un kök bileşeni de Dialog gibi open ve onOpenChange kabul ettiği için, pencereyi bir tablo satırındaki menüden açmak gibi durumlarda yukarıdaki kontrollü kalıbı aynen uygulayabilirsiniz.
Dialog mu Alert Dialog mu?

| Özellik | Dialog | Alert Dialog |
|---|---|---|
| Belgedeki tanım | Alttaki içeriği etkisiz bırakan genel pencere | Önemli içerikle kesen ve yanıt bekleyen modal pencere |
| Radix ilkeli | @radix-ui/react-dialog | @radix-ui/react-alert-dialog |
| Köşedeki kapatma düğmesi | Var (showCloseButton ile kapatılabilir) | Yok |
| Hazır düğme parçaları | DialogClose | AlertDialogAction ve AlertDialogCancel |
| Tipik kullanım | Form, ayrıntı, paylaşım | Silme, çıkış, geri alınamaz işlem onayı |
Küçük ekranlarda alttan açılan bir panel istiyorsanız Dialog yerine Drawer bileşenini düşünün; belgedeki responsive örnek geniş ekranda Dialog, dar ekranda Drawer gösterir. Bu örnek Sheet ve Drawer yazısında ayrıntılı olarak ele alınıyor.
Sık yapılan hatalar
- Menüyü Dialog'un dışında bırakmak: Context Menu ya da Dropdown Menu içinden dialog açarken menü
Dialogkökünün içinde olmalıdır; ya da Dropdown Menu sayfasındaki gibimodal={false}ile kontrollü pencere kullanmalısınız. - Başlığı ve açıklamayı atlamak:
DialogTitleveDialogDescriptionpencerenin ne olduğunu anlatan parçalardır. Görsel olarak gizlemek istiyorsanız kaldırmak yerinesr-onlysınıfı verin; depodakiCommandDialogkaynağı da başlığını bu şekilde gizler. Erişilebilirlik temelleri için ARIA rehberine bakın. - Tetikleyicide asChild unutmak:
<DialogTrigger>içine doğrudanButtonkoyarsanız iç içe iki düğme oluşur. Kendi butonunuzu kullanıyorsanızasChildekleyin. - Geri alınamaz işlem için Dialog kullanmak: belge onay bekleyen durumlar için ayrı bir bileşen sunar. Silme onayı için Alert Dialog daha uygun bir seçimdir.
- Genişliği bileşen dosyasında değiştirmek: tek bir pencere için
className="sm:max-w-[425px]"yeterlidir; dosyadakism:max-w-lgdeğerini değiştirmek projedeki bütün pencereleri etkiler. - Kontrollü kullanımda onOpenChange vermemek: yalnızca
openveriponOpenChangebağlamazsanız bileşen kapanmak istediğinde durumunuz güncellenmez.
Sık Sorulan Sorular
Dialog'daki çarpı düğmesini nasıl kaldırırım?
Depodaki kaynak koda göre DialogContent bileşenine showCloseButton={false} verirsiniz. Kapatmayı yine de mümkün kılmak için DialogClose ile sarılmış kendi düğmenizi ekleyin.
Alert Dialog dışarı tıklayınca kapanır mı?
shadcn/ui belgesi bu konuda ayrı bir açıklama yapmaz; davranış Radix Alert Dialog ilkelinden gelir. Ayrıntıyı belgede bağlantısı verilen Radix sayfasından kontrol edin. shadcn/ui tarafında bilinen şey, bileşende köşe kapatma düğmesi olmadığı ve kapatmanın iki düğmeyle tasarlandığıdır.
Pencere boyutunu nasıl değiştiririm?
DialogContent bileşenine className verin. Belge örnekleri sm:max-w-[425px] ve sm:max-w-md gibi sınıflar kullanır. Sınıflar cn() ile birleştirildiği için sizin değeriniz varsayılanı ezer.
Bir dropdown menü öğesinden nasıl dialog açarım?
İki belgelenmiş yol var: menüyü Dialog kökünün içine alıp öğeyi DialogTrigger asChild ile sarmak ya da menüye modal={false} verip öğenin onSelect olayında kontrollü bir dialogun durumunu true yapmak.
Dialog'u Next.js sayfasında kullanırken nelere dikkat etmeliyim?
dialog.tsx ve alert-dialog.tsx dosyaları "use client" satırıyla başlar, yani istemci bileşenidir. Pencereyi useState ile kontrol eden kendi bileşeninizin dosyasına da "use client" yazmanız gerekir. Kurulumun Next.js tarafı shadcn/ui Next.js kurulumu yazısında, App Router kavramları ise Next.js App Router yazısında anlatılıyor.
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 · Sheet ve Drawer · Dropdown Menu, Context Menu ve Menubar · Command paleti · Field bileşeni · ARIA rol ve öznitelikleri