Apa itu Shadcn/UI? Tutorial Pemula untuk Memulai

Audrey Lopez

Audrey Lopez

14 June 2025

Apa itu Shadcn/UI? Tutorial Pemula untuk Memulai

Bagi pengembang web, pencarian toolkit UI yang sempurna adalah upaya yang tiada henti. Selama bertahun-tahun, pengembang React mengandalkan pustaka komponen tradisional seperti Material-UI (MUI), Ant Design, dan Chakra UI. Pustaka ini menawarkan banyak komponen siap pakai, menjanjikan percepatan pengembangan. Namun, seringkali ada kompromi: kurangnya kontrol, penggantian gaya (style overrides) yang terasa seperti perjuangan, dan ukuran bundel yang membengkak.

Hadir Shadcn UI, sebuah pendekatan pengubah paradigma yang menggemparkan komunitas React. Ini bukanlah pustaka komponen seperti yang biasa Anda gunakan; ini sesuatu yang lebih baik. Ini adalah kumpulan komponen yang dirancang dengan indah, mudah diakses (accessible), dan sangat dapat digunakan kembali (reusable) yang tidak Anda instal dari npm sebagai dependensi—Anda menyalinnya langsung ke dalam proyek Anda.

Tutorial komprehensif setebal 4000 kata ini akan menjadi panduan definitif Anda, membawa Anda dari pemula total hingga praktisi Shadcn UI yang percaya diri. Kita akan menjelajahi filosofi dasarnya, menelusuri pengaturan terperinci, membangun UI yang kompleks, menguasai tema (theming) dan penanganan formulir tingkat lanjut, serta membahas praktik terbaik untuk aplikasi skala besar. Bersiaplah untuk memikirkan kembali apa yang Anda harapkan dari toolkit UI.

💡
Ingin alat Pengujian API yang hebat yang menghasilkan Dokumentasi API yang indah?

Ingin platform Terintegrasi, All-in-One untuk Tim Pengembang Anda agar bekerja sama dengan produktivitas maksimum?

Apidog memenuhi semua permintaan Anda, dan menggantikan Postman dengan harga yang jauh lebih terjangkau!
button

Filosofi Shadcn UI - Cara Baru Membangun

Sebelum menulis satu baris kode pun, sangat penting untuk memahami mengapa Shadcn UI ada dan masalah apa yang dipecahkannya. Memahami filosofi inti ini adalah kunci untuk membuka potensi penuhnya.

Apa yang Bukan Shadcn UI

Apa Itu Shadcn UI

Keunggulan utama dari model ini adalah perpaduan antara kecepatan dan kontrol. Anda mendapatkan kecepatan awal menggunakan komponen siap pakai tanpa mengorbankan fleksibilitas dan kemudahan pemeliharaan jangka panjang yang berasal dari kepemilikan kode Anda sendiri.


Menyiapkan Panggung - Pengaturan Proyek dan Instalasi

Mari beralih dari teori ke praktik. Kita akan menyiapkan proyek baru dari awal. Untuk panduan ini, kita akan menggunakan **Next.js** secara utama, karena komponen server dan perutean berbasis filenya sangat selaras dengan etos Shadcn UI. Kita juga akan membahas singkat pengaturan untuk Vite.

Langkah 1: Prasyarat Lingkungan

Pastikan lingkungan pengembangan Anda siap. Anda akan memerlukan:

Langkah 2: Membuat Aplikasi Next.js Baru

Buka terminal Anda dan jalankan perintah berikut untuk memulai proyek Next.js baru.Bash

npx create-next-app@latest my-pro-shadcn-app --typescript --tailwind --eslint

Perintah ini membuat kerangka aplikasi baru di direktori bernama my-pro-shadcn-app. Kita telah menyertakan beberapa flag penting:

Pemasang akan menanyakan beberapa pertanyaan. Ini adalah pilihan yang direkomendasikan untuk pengaturan Next.js 14+ modern:

✔ Would you like to use `src/` directory? … No / **Yes**
✔ Would you like to use App Router? (recommended) … No / **Yes**
✔ Would you like to customize the default import alias? … **No** / Yes

Menggunakan App Router adalah praktik standar, dan direktori src/ membantu dalam mengatur kode. Setelah selesai, navigasikan ke proyek baru Anda:Bash

cd my-pro-shadcn-app

Langkah 3: Perintah init - Menghidupkan Shadcn UI

Ini adalah langkah terpenting. Shadcn UI menyediakan alat CLI untuk mengonfigurasi proyek Anda. Jalankan perintah berikut dari direktori root proyek Anda:Bash

npx shadcn-ui@latest init

Ini akan memicu kuesioner interaktif untuk mengatur proyek Anda. Mari kita uraikan setiap pertanyaan dan signifikansinya:

Setelah Anda mengonfirmasi, CLI melakukan keajaibannya:

  1. Menginstal Dependensi: Ini menambahkan paket yang diperlukan seperti tailwindcss-animate dan class-variance-authority.
  2. Membuat components.json: Menyimpan pilihan konfigurasi Anda.
  3. Memperbarui tailwind.config.ts: Menyuntikkan plugin Shadcn UI dan konfigurasi tema.
  4. Memperbarui globals.css: Menambahkan blok besar variabel CSS yang mendefinisikan seluruh palet warna, radius sudut (border radii), dan banyak lagi.
  5. Membuat lib/utils.ts: File ini mengekspor fungsi pembantu cn, yang merupakan utilitas cerdas untuk menggabungkan kelas Tailwind CSS secara kondisional.

Proyek Anda sekarang sepenuhnya dikonfigurasi.

(Alternatif: Pengaturan Vite)

Jika Anda menggunakan Vite dengan React, prosesnya sangat mirip. Setelah menyiapkan proyek Vite + React + TS, Anda akan menginstal Tailwind CSS secara manual lalu menjalankan npx shadcn-ui@latest init. CLI cukup pintar untuk mendeteksi pengaturan Vite dan akan menanyakan pertanyaan yang sedikit berbeda tentang lokasi file (misalnya, index.css alih-alih globals.css).


Membangun UI - Dari Komponen Sederhana hingga Tata Letak Kompleks

Dengan pengaturan selesai, mari kita mulai membangun. Alur kerja intinya adalah: identifikasi kebutuhan, tambahkan komponen, gunakan.

Langkah 4: Menambahkan dan Menggunakan Komponen Pertama Anda

Mari kita bersihkan boilerplate Next.js default dan bangun antarmuka sederhana.

1. Tambahkan Tombol:Bash

npx shadcn-ui@latest add button

Perhatikan apa yang terjadi: file baru, src/components/ui/button.tsx, dibuat. Ini adalah tombol Anda. Anda memilikinya.

2. Tambahkan Kartu:Bash

npx shadcn-ui@latest add card

Perintah ini lebih menarik. Ini membuat src/components/ui/card.tsx. Jika Anda memeriksa file ini, Anda akan melihatnya mengekspor beberapa komponen: Card, CardHeader, CardTitle, CardDescription, CardContent, dan CardFooter. Ini adalah pola umum untuk komponen gabungan (compound components).

3. Bangun UI:

Sekarang, buka src/app/page.tsx dan ganti isinya dengan berikut ini:TypeScript

import { Button } from "@/components/ui/button";
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input"; // We'll add this next
import { Label } from "@/components/ui/label";   // And this

export default function Home() {
  return (
    <main className="flex min-h-screen items-center justify-center bg-background p-8">
      <Card className="w-full max-w-md">
        <CardHeader>
          <CardTitle className="text-2xl">Create Project</CardTitle>
          <CardDescription>
            Deploy your new project in one-click.
          </CardDescription>
        </CardHeader>
        <CardContent className="grid gap-4">
          <div className="grid gap-2">
            <Label htmlFor="name">Name</Label>
            <Input id="name" placeholder="Name of your project" />
          </div>
          <div className="grid gap-2">
            <Label htmlFor="framework">Framework</Label>
            {/* We'll replace this with a Select component later */}
            <Input id="framework" placeholder="e.g. Next.js" />
          </div>
        </CardContent>
        <CardFooter>
          <Button className="w-full">Deploy</Button>
        </CardFooter>
      </Card>
    </main>
  );
}

Kode kita belum akan berjalan karena kita kehilangan komponen Input dan Label. Mari kita tambahkan:Bash

npx shadcn-ui@latest add input
npx shadcn-ui@latest add label

Sekarang, jalankan server pengembangan Anda:Bash

npm run dev

Navigasikan ke http://localhost:3000. Anda akan melihat formulir yang bersih dan terlihat profesional di dalam kartu. Perhatikan bagaimana kita menggunakan kelas utilitas seperti w-full, max-w-md, dan grid langsung di JSX kita untuk mengontrol tata letak. Ini adalah kekuatan menggabungkan Shadcn dan Tailwind CSS.

Langkah 5: Memperkenalkan Komponen yang Lebih Canggih

Input statis itu bagus, tetapi aplikasi nyata memerlukan elemen interaktif. Mari kita tingkatkan formulir kita.

1. Tambahkan Komponen Select: Input "Framework" seharusnya berupa dropdown. Mari kita tambahkan komponen Select. Yang satu ini lebih kompleks dan memiliki dependensi pada komponen lain.Bash

npx shadcn-ui@latest add select

CLI itu pintar. Ia akan melihat bahwa Select memerlukan komponen Popover untuk berfungsi dan akan meminta izin Anda untuk menginstalnya serta dependensinya. Ini adalah fitur fantastis yang mencegah Anda harus melacak dependensi secara manual.

2. Integrasikan Komponen Select: Ganti Input untuk "Framework" di src/app/page.tsx dengan komponen Select yang baru.TypeScript

// Add these imports at the top
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";

// ... inside the CardContent
<div className="grid gap-2">
  <Label htmlFor="framework">Framework</Label>
  <Select>
    <SelectTrigger id="framework">
      <SelectValue placeholder="Select a framework" />
    </SelectTrigger>
    <SelectContent>
      <SelectItem value="nextjs">Next.js</SelectItem>
      <SelectItem value="sveltekit">SvelteKit</SelectItem>
      <SelectItem value="astro">Astro</SelectItem>
      <SelectItem value="nuxt">Nuxt.js</SelectItem>
    </SelectContent>
  </Select>
</div>

Segarkan browser Anda. Anda sekarang memiliki dropdown select yang berfungsi penuh dan mudah diakses (accessible), lengkap dengan animasi dan navigasi keyboard yang tepat, semua berkat Radix UI yang bekerja di balik layar.

3. Menambahkan Umpan Balik Pengguna dengan Toast: Apa yang terjadi ketika pengguna mengklik "Deploy"? Kita harus memberi mereka umpan balik. Komponen Toast sangat cocok untuk ini.

Pertama, tambahkan:Bash

npx shadcn-ui@latest add toast

Selanjutnya, untuk menggunakan toast, Anda perlu menambahkan komponen <Toaster /> ke tata letak root Anda agar dapat ditampilkan di mana saja di aplikasi. Buka src/app/layout.tsx dan modifikasi:TypeScript

import { Toaster } from "@/components/ui/toaster" // Import the Toaster

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Toaster /> {/* Add it here, just before closing body */}
      </body>
    </html>
  )
}

Sekarang, kita memerlukan cara untuk *memicu* toast. Kita akan menggunakan hook useToast. Mari kita perbarui src/app/page.tsx untuk menjadikannya komponen klien dan menangani klik tombol.TypeScript

'use client'; // <-- Add this at the very top of the file

// ... other imports
import { useToast } from "@/components/ui/use-toast";

export default function Home() {
  const { toast } = useToast(); // Get the toast function from the hook

  function handleDeploy() {
    toast({
      title: "Deployment Scheduled!",
      description: "Your project 'Name of your project' is being deployed.",
      duration: 5000,
    });
  }

  return (
    <main className="flex min-h-screen items-center justify-center bg-background p-8">
      <Card className="w-full max-w-md">
        {/* ... CardHeader and CardContent ... */}
        <CardFooter>
          <Button className="w-full" onClick={handleDeploy}> {/* Add onClick handler */}
            Deploy
          </Button>
        </CardFooter>
      </Card>
    </main>
  );
}

Sekarang, ketika Anda mengklik tombol "Deploy", notifikasi yang ramping akan muncul di sudut layar Anda.


Membangun Formulir Profesional dengan Validasi

Sebagian besar aplikasi dunia nyata memerlukan penanganan formulir yang tangguh, termasuk validasi sisi klien. Cara resmi untuk menangani ini dengan Shadcn UI adalah dengan menggabungkannya dengan react-hook-form untuk manajemen state dan zod untuk validasi skema. Mari kita bangun.

Langkah 6: Menginstal Dependensi Formulir

Pertama, mari kita instal pustaka yang diperlukan:Bash

npm install react-hook-form zod @hookform/resolvers

Langkah 7: Menambahkan Komponen Form Shadcn

Shadcn UI menyediakan komponen Form khusus yang berfungsi sebagai pembungkus untuk menghubungkan react-hook-form dengan komponen UI Anda secara mulus.Bash

npx shadcn-ui@latest add form

Ini akan menambahkan src/components/ui/form.tsx. File ini menyediakan serangkaian komponen yang sadar konteks (Form, FormField, FormItem, FormLabel, FormControl, FormDescription, FormMessage) yang secara drastis mengurangi boilerplate.

Langkah 8: Membuat Skema Validasi

Di src/app/page.tsx Anda, mari kita definisikan bentuk dan aturan data formulir kita menggunakan zod.TypeScript

// Add these imports at the top
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import {
  Form,
  FormControl,
  FormDescription,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form";

Sekarang, mari kita buat skema tepat di atas komponen Home kita:TypeScript

const formSchema = z.object({
  projectName: z.string().min(2, {
    message: "Nama proyek minimal 2 karakter.",
  }).max(50, {
    message: "Nama proyek tidak boleh melebihi 50 karakter.",
  }),
  framework: z.string({
    required_error: "Silakan pilih kerangka kerja untuk ditampilkan.",
  }),
});

Skema ini mendefinisikan dua field: projectName harus berupa string antara 2 dan 50 karakter, dan framework adalah string yang wajib diisi.

Langkah 9: Menghubungkan Formulir

Sekarang, mari kita refaktor komponen Home kita untuk menggunakan semua alat baru ini.TypeScript

export default function Home() {
  const { toast } = useToast();

  // 1. Define your form.
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      projectName: "",
    },
  });

  // 2. Define a submit handler.
  function onSubmit(values: z.infer<typeof formSchema>) {
    // Do something with the form values.
    // ✅ This will be type-safe and validated.
    console.log(values);
    toast({
      title: "Anda mengirimkan nilai berikut:",
      description: (
        <pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
          <code className="text-white">{JSON.stringify(values, null, 2)}</code>
        </pre>
      ),
    });
  }

  // 3. Build the JSX with Shadcn's Form components
  return (
    <main className="flex min-h-screen items-center justify-center bg-background p-8">
      <Card className="w-full max-w-md">
        <CardHeader>
          <CardTitle className="text-2xl">Buat Proyek</CardTitle>
          <CardDescription>
            Deploy proyek baru Anda dalam satu klik.
          </CardDescription>
        </CardHeader>
        <CardContent>
          <Form {...form}>
            <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
              <FormField
                control={form.control}
                name="projectName"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>Nama</FormLabel>
                    <FormControl>
                      <Input placeholder="Nama proyek Anda" {...field} />
                    </FormControl>
                    <FormDescription>
                      Ini adalah nama tampilan publik Anda.
                    </FormDescription>
                    <FormMessage /> {/* Displays validation errors */}
                  </FormItem>
                )}
              />
              <FormField
                control={form.control}
                name="framework"
                render={({ field }) => (
                  <FormItem>
                    <FormLabel>Kerangka Kerja</FormLabel>
                    <Select onValueChange={field.onChange} defaultValue={field.value}>
                      <FormControl>
                        <SelectTrigger>
                          <SelectValue placeholder="Pilih kerangka kerja" />
                        </SelectTrigger>
                      </FormControl>
                      <SelectContent>
                        <SelectItem value="nextjs">Next.js</SelectItem>
                        <SelectItem value="sveltekit">SvelteKit</SelectItem>
                        <SelectItem value="astro">Astro</SelectItem>
                        <SelectItem value="nuxt">Nuxt.js</SelectItem>
                      </SelectContent>
                    </Select>
                    <FormDescription>
                      Kerangka kerja yang ingin Anda deploy.
                    </FormDescription>
                    <FormMessage />
                  </FormItem>
                )}
              />
              <Button type="submit" className="w-full">Deploy</Button>
            </form>
          </Form>
        </CardContent>
      </Card>
    </main>
  );
}

Ini adalah bagian kode yang signifikan, tetapi ini adalah pola yang sangat kuat dan terukur. Komponen FormField menangani semua koneksi state, dan FormMessage secara otomatis menampilkan kesalahan validasi yang benar dari skema zod Anda ketika pengguna berinteraksi dengan field. Coba kirimkan formulir dengan nama proyek kosong untuk melihat validasi beraksi.


Menguasai Tema (Theming) dan Penyesuaian

Kekuatan sejati Shadcn UI terungkap ketika Anda mulai menjadikannya milik Anda sendiri.

Langkah 10: Tema Tingkat Lanjut dengan Variabel CSS

Seluruh tema Anda didefinisikan oleh variabel CSS di src/app/globals.css. Buka file ini dan cari blok :root dan .dark.CSS

/* Example from globals.css */
:root {
  --background: 0 0% 100%;
  --foreground: 222.2 84% 4.9%;
  --primary: 222.2 47.4% 11.2%;
  --primary-foreground: 210 40% 98%;
  /* ... and many more */
  --radius: 0.5rem;
}

.dark {
  --background: 222.2 84% 4.9%;
  --foreground: 210 40% 98%;
  --primary: 210 40% 98%;
  --primary-foreground: 222.2 47.4% 11.2%;
  /* ... */
}

Menerapkan Mode Gelap:

Shadcn telah dikonfigurasi sebelumnya untuk mode gelap berkat blok kelas .dark dan strategi darkMode: "class" Tailwind di tailwind.config.ts. Yang Anda perlukan hanyalah cara untuk mengaktifkan kelas dark pada elemen <html>. Pustaka populer untuk ini adalah next-themes.

  1. Instal: npm install next-themes
  2. Buat komponen ThemeProvider (src/components/theme-provider.tsx): TypeScript
"use client"
import * as React from "react"
import { ThemeProvider as NextThemesProvider } from "next-themes"
import { type ThemeProviderProps } from "next-themes/dist/types"

export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
  return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}
  1. Bungkus RootLayout Anda dalam provider ini (src/app/layout.tsx): TypeScript
import { ThemeProvider } from "@/components/theme-provider"

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <ThemeProvider
          attribute="class"
          defaultTheme="system"
          enableSystem
          disableTransitionOnChange
        >
          {children}
          <Toaster />
        </ThemeProvider>
      </body>
    </html>
  )
}
  1. Terakhir, buat tombol toggle (misalnya, src/components/mode-toggle.tsx): TypeScript
"use client"
import * as React from "react"
import { Moon, Sun } from "lucide-react"
import { useTheme } from "next-themes"
import { Button } from "@/components/ui/button"

export function ModeToggle() {
  const { theme, setTheme } = useTheme()

  return (
    <Button
      variant="outline"
      size="icon"
      onClick={() => setTheme(theme === "light" ? "dark" : "light")}
    >
      <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
      <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
      <span className="sr-only">Toggle theme</span>
    </Button>
  )
}

Anda sekarang dapat menempatkan <ModeToggle /> ini di mana saja di aplikasi Anda untuk mendapatkan toggle mode gelap yang sadar sistem dan dapat ditimpa oleh pengguna.

Langkah 11: Menyesuaikan Kode Sumber Komponen

Ini adalah kekuatan super utama. Katakanlah Anda menginginkan varian "success" baru untuk tombol Anda yang memiliki latar belakang hijau.

Buka src/components/ui/button.tsx. Temukan definisi buttonVariants. Ini menggunakan cva (Class Variance Authority). Cukup tambahkan varian baru:TypeScript

const buttonVariants = cva(
  // ... base styles
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground hover:bg-primary/90",
        destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
        outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
        secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
        ghost: "hover:bg-accent hover:text-accent-foreground",
        link: "text-primary underline-offset-4 hover:underline",
        success: "bg-green-600 text-white hover:bg-green-600/90", // Varian baru kita
      },
      // ... size variants
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

Itu saja. Anda sekarang dapat menggunakannya dalam kode Anda: <Button variant="success">Success</Button>. Anda tidak perlu menulis penggantian CSS yang kompleks. Anda hanya mengedit kode sumber komponen itu sendiri. Alur kerja ini sederhana, dapat diprediksi, dan sangat kuat.


Bagian 6: Praktik Terbaik dan Jalan ke Depan

Seiring pertumbuhan aplikasi Anda, berikut adalah beberapa praktik terbaik yang perlu diingat.

Kesimpulan: Anda Adalah Penulis Pustaka

Anda kini telah melakukan perjalanan dari filosofi inti Shadcn UI hingga mengimplementasikan pola tingkat lanjut di dunia nyata. Anda telah melihat bahwa inovasi sejatinya bukan hanya komponen itu sendiri, tetapi pergeseran paradigma yang diwakilinya. Ini menggerakkan pengembang dari sekadar *konsumen* pustaka menjadi *kurator* dan *pemilik* toolkit UI mereka sendiri.

Dengan memberi Anda kode sumber mentah, membangun di atas fondasi kokoh Tailwind CSS dan Radix UI, serta menyediakan pengalaman CLI yang mulus, Shadcn UI mencapai keseimbangan sempurna antara kecepatan pengembangan awal dan kemudahan pemeliharaan jangka panjang serta kebebasan kreatif. Anda tidak lagi dibatasi oleh sistem desain orang lain. Komponen dalam proyek Anda adalah milik Anda sendiri—untuk dimodifikasi, diperluas, dan disempurnakan.

Masa depan UI aplikasi Anda tidak lagi berada di tangan dependensi pihak ketiga; itu ada di folder components Anda. Selamat membangun.

💡
Ingin alat Pengujian API yang hebat yang menghasilkan Dokumentasi API yang indah?

Ingin platform Terintegrasi, All-in-One untuk Tim Pengembang Anda agar bekerja sama dengan produktivitas maksimum?

Apidog memenuhi semua permintaan Anda, dan menggantikan Postman dengan harga yang jauh lebih terjangkau!
button

Mengembangkan API dengan Apidog

Apidog adalah alat pengembangan API yang membantu Anda mengembangkan API dengan lebih mudah dan efisien.