Atomic Design: Cara Membangun Komponen UI yang Terstruktur dan Scalable

May 27, 2026 (Today)

6 min read

...

Pernah membuka proyek lama dan kebingungan mencari komponen tombol yang "sedikit berbeda" dari yang lain? Atau mendapati ada lima versi Card yang hampir sama tersebar di berbagai folder?

Atomic Design hadir untuk menyelesaikan masalah itu.

Di artikel ini, kita akan membahas metodologi Atomic Design dari Brad Frost — apa itu, bagaimana cara kerjanya, dan bagaimana menerapkannya dalam proyek React atau Next.js nyata.


Apa Itu Atomic Design?

Atomic Design adalah metodologi untuk merancang sistem komponen UI yang diperkenalkan oleh Brad Frost pada 2013. Ide utamanya sederhana: pinjam cara berpikir dari kimia.

Dalam kimia, materi tersusun dari atom → molekul → organisme. Brad Frost mengadaptasi konsep ini ke dunia desain antarmuka:

Daripada langsung mendesain halaman, kita bangun antarmuka dari komponen terkecil dan paling sederhana, lalu susun ke atas menjadi tampilan yang lebih kompleks.

Metodologi ini terdiri dari 5 level:

  1. Atoms (Atom)
  2. Molecules (Molekul)
  3. Organisms (Organisme)
  4. Templates (Template)
  5. Pages (Halaman)

Mari kita bedah satu per satu.


Level 1: Atoms

Atom adalah unit terkecil yang tidak bisa dipecah lebih jauh lagi tanpa kehilangan fungsinya. Dalam HTML, ini adalah elemen-elemen dasar seperti <button>, <input>, <label>, <img>, atau <a>.

Dalam konteks komponen React, atom bisa berupa:

// components/atoms/Button.tsx type ButtonProps = { label: string; variant?: 'primary' | 'secondary' | 'ghost'; onClick?: () => void; disabled?: boolean; }; export function Button({ label, variant = 'primary', onClick, disabled }: ButtonProps) { const base = 'px-4 py-2 rounded-lg font-medium transition-colors'; const variants = { primary: 'bg-blue-600 text-white hover:bg-blue-700', secondary: 'bg-gray-100 text-gray-800 hover:bg-gray-200', ghost: 'text-blue-600 hover:bg-blue-50', }; return ( <button className={`${base} ${variants[variant]}`} onClick={onClick} disabled={disabled} > {label} </button> ); }
// components/atoms/Input.tsx type InputProps = { placeholder?: string; value: string; onChange: (value: string) => void; type?: 'text' | 'email' | 'password'; }; export function Input({ placeholder, value, onChange, type = 'text' }: InputProps) { return ( <input type={type} placeholder={placeholder} value={value} onChange={(e)=> onChange(e.target.value)} className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" /> ); }
// components/atoms/Label.tsx export function Label({ text, htmlFor }: { text: string; htmlFor?: string }) { return ( <label htmlFor={htmlFor} className="text-sm font-medium text-gray-700"> {text} </label> ); }

Atom bersifat standalone — tidak bergantung pada komponen lain dan bisa dipakai di mana saja.


Level 2: Molecules

Molekul adalah kombinasi dari beberapa atom yang bekerja bersama sebagai satu unit fungsional. Ini adalah level di mana komponen mulai memiliki "kepribadian" — misalnya, Label + Input + teks error menjadi satu FormField.

// components/molecules/FormField.tsx import { Input } from '@/components/atoms/Input'; import { Label } from '@/components/atoms/Label'; type FormFieldProps = { label: string; id: string; placeholder?: string; value: string; onChange: (value: string) => void; error?: string; type?: 'text' | 'email' | 'password'; }; export function FormField({ label, id, error, ...inputProps }: FormFieldProps) { return ( <div className="flex flex-col gap-1"> <Label text={label} htmlFor={id} /> <Input {...inputProps} /> {error && <span className="text-xs text-red-500">{error}</span>} </div> ); }
// components/molecules/SearchBar.tsx import { Input } from '@/components/atoms/Input'; import { Button } from '@/components/atoms/Button'; type SearchBarProps = { value: string; onChange: (value: string) => void; onSearch: () => void; }; export function SearchBar({ value, onChange, onSearch }: SearchBarProps) { return ( <div className="flex gap-2"> <Input value={value} onChange={onChange} placeholder="Cari sesuatu..." /> <Button label="Cari" onClick={onSearch} /> </div> ); }

Molekul satu tujuan (single purpose) — SearchBar hanya urusin search, FormField hanya urusin input form. Fokus ini yang membuat mereka mudah di-reuse.


Level 3: Organisms

Organisme adalah bagian UI yang lebih kompleks, terbentuk dari kombinasi atom, molekul, atau bahkan organisme lainnya. Ini adalah bagian yang sudah mulai terlihat seperti "blok konten nyata" di halaman web.

Contoh organisme: navbar, form login lengkap, card produk, header artikel.

// components/organisms/LoginForm.tsx import { FormField } from '@/components/molecules/FormField'; import { Button } from '@/components/atoms/Button'; import { useState } from 'react'; export function LoginForm({ onSubmit }: { onSubmit: (email: string, password: string) => void }) { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [errors, setErrors] = useState({ email: '', password: '' }); function validate() { const newErrors = { email: '', password: '' }; if (!email.includes('@')) newErrors.email = 'Email tidak valid'; if (password.length < 8) newErrors.password = 'Password minimal 8 karakter'; setErrors(newErrors); return !newErrors.email && !newErrors.password; } function handleSubmit() { if (validate()) onSubmit(email, password); } return ( <div className="flex flex-col gap-4 p-6 bg-white rounded-xl shadow-md w-full max-w-sm"> <h2 className="text-xl font-bold text-gray-900">Masuk ke Akun</h2> <FormField label="Email" id="email" type="email" placeholder="kamu@email.com" value={email} onChange={setEmail} error={errors.email} /> <FormField label="Password" id="password" type="password" placeholder="Minimal 8 karakter" value={password} onChange={setPassword} error={errors.password} /> <Button label="Masuk" onClick={handleSubmit} /> </div> ); }
// components/organisms/Navbar.tsx import { Button } from '@/components/atoms/Button'; import { SearchBar } from '@/components/molecules/SearchBar'; import { useState } from 'react'; import Link from 'next/link'; export function Navbar() { const [query, setQuery] = useState(''); return ( <header className="flex items-center justify-between px-6 py-4 border-b border-gray-200"> <Link href="/" className="text-xl font-bold text-gray-900"> MyApp </Link> <SearchBar value={query} onChange={setQuery} onSearch={()=> console.log(query)} /> <div className="flex gap-2"> <Button label="Masuk" variant="ghost" /> <Button label="Daftar" variant="primary" /> </div> </header> ); }

Organisme sudah memiliki konteks bisnisLoginForm tahu bahwa dirinya untuk proses login, Navbar tahu bahwa dirinya adalah navigasi utama.


Level 4: Templates

Template adalah kerangka halaman — susunan organisme yang mendefinisikan layout tanpa konten nyata. Ini seperti wireframe berisi komponen, bukan konten final.

Template berfokus pada struktur dan tata letak, bukan data.

// components/templates/AuthLayout.tsx import { Navbar } from '@/components/organisms/Navbar'; type AuthLayoutProps = { children: React.ReactNode; }; export function AuthLayout({ children }: AuthLayoutProps) { return ( <div className="min-h-screen bg-gray-50"> <Navbar /> <main className="flex items-center justify-center py-16 px-4"> {children} </main> </div> ); }
// components/templates/DashboardLayout.tsx import { Navbar } from '@/components/organisms/Navbar'; import { Sidebar } from '@/components/organisms/Sidebar'; type DashboardLayoutProps = { children: React.ReactNode; }; export function DashboardLayout({ children }: DashboardLayoutProps) { return ( <div className="min-h-screen bg-gray-50"> <Navbar /> <div className="flex"> <Sidebar /> <main className="flex-1 p-6">{children}</main> </div> </div> ); }

Template menjawab pertanyaan: "Bagaimana halaman ini terstruktur?", bukan "Apa kontennya?"


Level 5: Pages

Halaman adalah instansi spesifik dari template yang diisi dengan konten nyata. Di sinilah data masuk, state dikelola, dan pengguna akhirnya berinteraksi.

// app/login/page.tsx import { AuthLayout } from '@/components/templates/AuthLayout'; import { LoginForm } from '@/components/organisms/LoginForm'; import { useRouter } from 'next/navigation'; export default function LoginPage() { const router = useRouter(); async function handleLogin(email: string, password: string) { // panggil API, simpan session, redirect await signIn(email, password); router.push('/dashboard'); } return ( <AuthLayout> <LoginForm onSubmit={handleLogin} /> </AuthLayout> ); }

Halaman adalah level paling konkret — kombinasi sempurna antara template dan data nyata yang menghasilkan pengalaman pengguna.


Struktur Folder yang Direkomendasikan

Terapkan hierarki ini langsung ke struktur folder proyekmu:

components/ ├── atoms/ ├── Button.tsx ├── Input.tsx ├── Label.tsx ├── Avatar.tsx └── Badge.tsx ├── molecules/ ├── FormField.tsx ├── SearchBar.tsx ├── UserCard.tsx └── Notification.tsx ├── organisms/ ├── LoginForm.tsx ├── Navbar.tsx ├── Sidebar.tsx └── ProductGrid.tsx └── templates/ ├── AuthLayout.tsx ├── DashboardLayout.tsx └── MarketingLayout.tsx

Halaman (pages/ atau app/) adalah level terakhir dan biasanya tidak masuk ke folder components/ — mereka sudah merupakan route Next.js.


Keuntungan Atomic Design

1. Konsistensi Visual

Karena semua komponen dibangun dari atom yang sama, tampilan selalu konsisten. Tidak ada lagi tombol biru dengan 4 ukuran berbeda yang tersebar di seluruh codebase.

2. Mudah Di-reuse

Atom dan molekul dirancang untuk dipakai ulang. Sekali buat Button, pakai di mana saja — tidak perlu copy-paste dan modifikasi manual.

3. Mudah Di-maintain

Perlu mengubah warna utama? Ubah di atom Button, otomatis berlaku di semua molekul dan organisme yang memakainya.

4. Onboarding Developer Lebih Cepat

Struktur yang jelas memudahkan developer baru memahami arsitektur proyek. Mereka tahu persis di mana mencari dan di mana menambah komponen baru.

5. Komunikasi Lebih Baik dengan Desainer

Atomic Design adalah bahasa bersama antara developer dan desainer. Desainer membuat design system dengan atoms dan molecules di Figma, developer mengimplementasikannya dengan cara yang sama.


Kapan Atomic Design Tidak Cocok?

Atomic Design bukan peluru ajaib. Ada situasi di mana ia bisa menjadi over-engineering:

  • Proyek kecil atau sekali pakai — jika proyekmu hanya 3–4 halaman dan tidak akan berkembang besar, struktur ini menambah kompleksitas tanpa manfaat nyata.
  • Tim solo dengan deadline ketat — membangun design system butuh investasi waktu di awal. Jika waktu sangat terbatas, mulailah dengan struktur sederhana dulu.
  • Prototipe / MVP cepat — fokuslah pada validasi produk dulu. Refactor ke Atomic Design setelah konsepnya terbukti.

Aturan praktisnya: jika proyekmu akan dikerjakan lebih dari 2 orang atau akan bertahan lebih dari 6 bulan, Atomic Design layak dipertimbangkan.


Ringkasan

LevelContohKarakteristik
AtomButton, Input, LabelPaling kecil, tidak bergantung pada yang lain
MolekulFormField, SearchBarKombinasi atom, satu tujuan
OrganismeLoginForm, NavbarPunya konteks bisnis, siap dipakai
TemplateAuthLayout, DashboardLayoutKerangka halaman, belum ada data nyata
HalamanLoginPage, DashboardPageInstansi final dengan data dan interaksi nyata

Atomic Design bukan tentang mengikuti aturan kaku — ini tentang cara berpikir dalam memecah masalah UI menjadi bagian-bagian yang lebih kecil dan mudah dikelola. Mulai dari atom, susun ke atas, dan kamu akan memiliki design system yang tumbuh bersama proyekmu.

Loading reactions...
Similar Posts

Here are some other articles you might find interesting.

Subscribe to my newsletter

A periodic update about my life, recent blog posts, how-tos, and discoveries.

NO SPAM. I never send spam. You can unsubscribe at any time!

Rafsan's Logo

I'm Rafsan — a Flutter-focused Software Engineer, Assistant Trainer, and workshop speaker. Thanks for visiting!

© 2026 Rafsan