shadcn/ui Nasıl Endüstri Standardı Oldu? 110K Yıldızlı Bileşen Devriminin Anatomisi
React ekosisteminde her yıl onlarca UI kütüphanesi doğar, büyür ve çoğu zaman sessizce ölür. Material UI, Ant Design, Chakra UI gibi devler yıllarca tahtlarını korudu. Ancak 2023 yılında sahneye çıkan shadcn/ui, hiçbir kurala uymadan — hatta kuralları tamamen yeniden yazarak — kısa sürede 110.000'den fazla GitHub yıldızına ulaştı ve adeta endüstri standardı haline geldi.
Peki bir geliştirici olan shadcn (Shadid Haque) bunu nasıl başardı? Ve daha önemlisi: bu yaklaşım neden bu kadar işe yarıyor?
Geleneksel UI Kütüphanelerinin Sorunu
Önce sorunu anlayalım. Klasik bir UI kütüphanesi kullandığınızda şu döngüye girersiniz:
npm installile paketi kurarsınız- Bileşenleri import edip kullanırsınız
- Özelleştirme yapmak istediğinizde
theme,sx,styled()gibi API'larla boğuşursunuz - Kütüphanenin CSS'iyle kendi stilleriniz çakışır
- Breaking change içeren bir major versiyon gelir, tüm projeyi güncellemeniz gerekir
- Kütüphanenin desteklemediği bir edge case'de "escape hatch" ararsınız
Bu sorunları herkes yaşadı. Material UI'da bir Button'ın border-radius'unu değiştirmek için 47 satır tema konfigürasyonu yazmak zorunda kalan tek kişi siz değilsiniz.
Asıl Sorun: Sahiplik
Geleneksel kütüphanelerde bileşenler sizin değildir. Onlar node_modules klasörünün derinliklerinde yaşar. Değiştiremezsiniz, sadece kütüphanenin sunduğu API yüzeyiyle etkileşime girersiniz. Bu, kütüphane yazarının öngörmediği her senaryo için bir duvar anlamına gelir.
shadcn/ui'nin Radikal Yaklaşımı: "Bu Bir Kütüphane Değil"
shadcn/ui'nin resmi web sitesindeki ilk cümle her şeyi özetler:
"This is NOT a component library. It's a collection of re-usable components that you can copy and paste into your apps."
Bu, pazarlama cümlesi değil — mimari bir karardır. shadcn/ui bir npm paketi olarak kurulmaz. Bunun yerine bir CLI aracı sunar ve bileşenleri doğrudan projenizin kaynak koduna kopyalar.
# shadcn/ui kurulumu — dikkat edin, bir paket kurmuyorsunuz
npx shadcn@latest init
# Bir bileşen ekleme — dosyalar projenize kopyalanır
npx shadcn@latest add button
npx shadcn@latest add dialog
npx shadcn@latest add data-tableBu komutu çalıştırdığınızda node_modules'a değil, projenizin components/ui/ klasörüne gerçek dosyalar yazılır:
src/
├── components/
│ └── ui/
│ ├── button.tsx ← Sizin dosyanız, istediğiniz gibi değiştirin
│ ├── dialog.tsx
│ ├── input.tsx
│ └── data-table.tsx
├── lib/
│ └── utils.ts ← cn() utility fonksiyonuTeknik Altyapı: Neden Bu Kadar Sağlam?
shadcn/ui'nin başarısı sadece "kopyala-yapıştır" felsefesinden ibaret değil. Altında üç güçlü teknoloji katmanı var:
1. Radix UI Primitives — Erişilebilirlik Temeli
Her shadcn/ui bileşeni, Radix UI primitive'lerinin üzerine inşa edilmiştir. Radix, headless (stilsiz) ama tamamen erişilebilir bileşenler sunar: klavye navigasyonu, ARIA attributeları, focus yönetimi — hepsi kutudan çıkar.
// shadcn/ui Dialog bileşeninin iç yapısı
import * as DialogPrimitive from "@radix-ui/react-dialog"
const Dialog = DialogPrimitive.Root
const DialogTrigger = DialogPrimitive.Trigger
const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogPrimitive.Portal>
<DialogPrimitive.Overlay className="fixed inset-0 z-50 bg-black/80" />
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 w-full max-w-lg translate-x-[-50%] translate-y-[-50%] rounded-lg border bg-background p-6 shadow-lg",
className
)}
{...props}
>
{children}
</DialogPrimitive.Content>
</DialogPrimitive.Portal>
))Burada dikkat edin: Radix erişilebilirliği sağlıyor, shadcn/ui ise Tailwind CSS ile görsel katmanı ekliyor. Sorumluluklar net bir şekilde ayrılmış.
2. Tailwind CSS — Stil Katmanı
Tüm stiller Tailwind CSS utility class'larıyla yazılır. Bu, birkaç kritik avantaj sağlar:
- Çakışma yok: Global CSS yok, her şey scoped utility class
- Özelleştirme kolay: Class'ı değiştirin, bitti
- Tema desteği: CSS custom properties ile karanlık/aydınlık tema
// Button bileşeni — tüm varyantlar Tailwind class'larıyla
import { cva, type VariantProps } from "class-variance-authority"
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
icon: "h-9 w-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)3. Class Variance Authority (CVA) — Varyant Yönetimi
Yukarıdaki kodda gördüğünüz cva fonksiyonu, class-variance-authority paketinden gelir. Bu, bileşen varyantlarını type-safe bir şekilde yönetmenizi sağlar:
// Kullanım — TypeScript otomatik tamamlama ile
<Button variant="destructive" size="lg">
Sil
</Button>
<Button variant="ghost" size="icon">
<Settings className="h-4 w-4" />
</Button>4. cn() Utility — Koşullu Class Birleştirme
shadcn/ui'nin en zarif detaylarından biri, clsx ve tailwind-merge birleşiminden oluşan cn() fonksiyonudur:
// lib/utils.ts
import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}Bu küçük fonksiyon, Tailwind class çakışmalarını otomatik olarak çözer:
// tailwind-merge sayesinde "p-4" yerine "p-8" kullanılır (çakışma çözülür)
cn("p-4 bg-red-500", "p-8")
// Sonuç: "bg-red-500 p-8"
// Koşullu class'lar
cn("base-class", isActive && "bg-primary", isDisabled && "opacity-50")Gerçek Dünya Kullanımı: Tam Bir Form Örneği
shadcn/ui'nin gücünü gerçek bir senaryoda görelim. Bir kullanıcı kayıt formu oluşturalım:
npx shadcn@latest add form input button label card"use client"
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import * as z from "zod"
import { Button } from "@/components/ui/button"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
const formSchema = z.object({
username: z.string().min(3, "Kullanıcı adı en az 3 karakter olmalı"),
email: z.string().email("Geçerli bir e-posta adresi girin"),
password: z.string().min(8, "Şifre en az 8 karakter olmalı"),
})
export function RegisterForm() {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
username: "",
email: "",
password: "",
},
})
function onSubmit(values: z.infer<typeof formSchema>) {
console.log(values)
}
return (
<Card className="w-full max-w-md mx-auto">
<CardHeader>
<CardTitle>Kayıt Ol</CardTitle>
<CardDescription>Hesabınızı oluşturun</CardDescription>
</CardHeader>
<CardContent>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<FormField
control={form.control}
name="username"
render={({ field }) => (
<FormItem>
<FormLabel>Kullanıcı Adı</FormLabel>
<FormControl>
<Input placeholder="kullaniciadi" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>E-posta</FormLabel>
<FormControl>
<Input type="email" placeholder="ornek@mail.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>Şifre</FormLabel>
<FormControl>
<Input type="password" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit" className="w-full">
Kayıt Ol
</Button>
</form>
</Form>
</CardContent>
</Card>
)
}Bu kodda shadcn/ui, React Hook Form ve Zod ile sorunsuz entegre çalışıyor. Ve en önemlisi: herhangi bir bileşeni değiştirmek isterseniz, doğrudan components/ui/ altındaki dosyayı açıp düzenleyebilirsiniz.
Neden Bu Kadar Popüler? 5 Kritik Faktör
1. Next.js Ekosistemiyle Mükemmel Uyum
Vercel'in kendi projelerinde shadcn/ui kullanması ve Next.js'in create-next-app template'lerinde yer alması, organik büyümeyi hızlandırdı. V0.dev (Vercel'in AI aracı) doğrudan shadcn/ui bileşenleri üretir.
2. AI Kod Üretimi İçin İdeal Format
ChatGPT, Claude, Cursor ve Copilot gibi araçlar shadcn/ui kodunu son derece iyi üretir. Bunun nedeni basit: bileşenler self-contained dosyalardır, karmaşık bir kütüphane API'si öğrenmeye gerek yoktur.
3. Sıfır Vendor Lock-in
Yarın shadcn/ui projesi kapansa bile kodunuz çalışmaya devam eder. Bileşenler sizin dosyalarınızdır; hiçbir dış bağımlılığa (Radix hariç) kilitli değilsiniz.
4. Tasarım Sistemi Kalitesinde Varsayılanlar
Bileşenler kutudan çıktığı haliyle profesyonel görünür. Geist font, tutarlı spacing, düzgün animasyonlar — hepsi varsayılan olarak gelir. Tema sistemi CSS custom properties üzerine kuruludur:
/* globals.css — tema değişkenleri */
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 95.9%;
--muted: 240 4.8% 95.9%;
--accent: 240 4.8% 95.9%;
--radius: 0.5rem;
}
.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
}
}5. Kompozisyon Odaklı API
shadcn/ui bileşenleri composition pattern kullanır. Tek bir monolitik prop API'si yerine, küçük parçaları birleştirirsiniz:
// Monolitik yaklaşım (geleneksel kütüphaneler)
<Dialog
title="Onay"
description="Emin misiniz?"
confirmText="Evet"
cancelText="Hayır"
onConfirm={handleConfirm}
onCancel={handleCancel}
footer={<CustomFooter />}
/>
// Kompozisyon yaklaşımı (shadcn/ui)
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Aç</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Onay</DialogTitle>
<DialogDescription>Emin misiniz?</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button variant="outline" onClick={handleCancel}>Hayır</Button>
<Button onClick={handleConfirm}>Evet</Button>
</DialogFooter>
</DialogContent>
</Dialog>İkinci yaklaşım daha fazla JSX gerektirir, ama sınırsız esneklik sunar. İstediğiniz yere istediğiniz bileşeni koyabilirsiniz.
Eleştiriler ve Sınırlamalar
Her teknoloji gibi shadcn/ui de mükemmel değil:
- Güncellemeler manuel: Bir bileşende bug fix yapıldığında, siz de kendi dosyanızı güncellemelisiniz (CLI'da
diffkomutu bu sorunu hafifletir) - Tailwind bağımlılığı: Tailwind CSS kullanmayan projelerde doğrudan kullanılamaz
- Bundle size kontrolü: Kullanmadığınız bileşenleri de projeye eklerseniz şişkinlik oluşabilir (ama tree-shaking çalışır)
- Büyük ekiplerde tutarsızlık: Herkes bileşenleri farklı şekilde değiştirirse kaos doğabilir
# Bileşen güncellemelerini kontrol etmek için
npx shadcn@latest diff buttonRakiplerle Karşılaştırma
| Özellik | shadcn/ui | Material UI | Chakra UI | Ant Design |
|---|---|---|---|---|
| Kurulum | CLI ile kopyalama | npm install | npm install | npm install |
| Sahiplik | Tam sahiplik | Kütüphane kontrolünde | Kütüphane kontrolünde | Kütüphane kontrolünde |
| Stil sistemi | Tailwind CSS | Emotion/styled | Styled System | Less/CSS Modules |
| Bundle etkisi | Sadece kullandıklarınız | Ağır | Orta | Çok ağır |
| Erişilebilirlik | Radix UI (mükemmel) | İyi | İyi | Orta |
| Öğrenme eğrisi | Düşük | Yüksek | Orta | Yüksek |
| TypeScript | Birinci sınıf | İyi | İyi | İyi |
2025'te shadcn/ui Ekosistemi
shadcn/ui artık sadece bir bileşen koleksiyonu değil, bir ekosistem haline geldi:
- shadcn/ui Charts: Recharts üzerine inşa edilmiş grafik bileşenleri
- shadcn/ui Blocks: Hazır sayfa bölümleri (dashboard, authentication, settings)
- shadcn/ui Themes: Topluluk tarafından oluşturulan tema koleksiyonları
- V0.dev entegrasyonu: Prompt'tan shadcn/ui kodu üretimi
- Topluluk registries: Üçüncü parti bileşen registry desteği
Sonuç
shadcn/ui, React ekosisteminde bir paradigma kayması yarattı. "Bileşen kütüphanesi" kavramını yeniden tanımlayarak sahiplik, esneklik ve şeffaflık ilkelerini ön plana çıkardı. 110.000'den fazla GitHub yıldızı bir hype'ın değil, gerçek bir ihtiyacın karşılanmasının sonucudur.
Bu yaklaşımın özü aslında çok basit: Geliştirici olarak kendi kodunuza sahip olun. Kütüphaneler ilham kaynağı olsun, hapishane değil.
Eğer yeni bir React projesi başlıyorsanız veya mevcut projenizin UI katmanını yeniden düşünüyorsanız, shadcn/ui'yi denemek artık bir tercih değil — neredeyse bir zorunluluk. Ama unutmayın: shadcn/ui size bileşenler verir, bu bileşenlerle ne yapacağınız tamamen size kalmış.
# Hadi başlayalım
npx shadcn@latest init