İçeriğe geç
Sedat Demir
Geri dön

shadcn/ui Nasıl Endüstri Standardı Oldu? 110K Yıldızlı Bileşen Devriminin Anatomisi

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:

  1. npm install ile paketi kurarsınız
  2. Bileşenleri import edip kullanırsınız
  3. Özelleştirme yapmak istediğinizde theme, sx, styled() gibi API'larla boğuşursunuz
  4. Kütüphanenin CSS'iyle kendi stilleriniz çakışır
  5. Breaking change içeren bir major versiyon gelir, tüm projeyi güncellemeniz gerekir
  6. 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-table

Bu 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 fonksiyonu

Teknik 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:

// 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:

# Bileşen güncellemelerini kontrol etmek için
npx shadcn@latest diff button

Rakiplerle 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:


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

Share this post on:

Sonraki Yazı
React Hook Form ve Zod v4 ile Type-Safe Form Validation Rehberi