nextjslayoutPemula4 mnt baca

Layout Dasar

UI bersama antar halaman: root layout dan nested layout.

Analogi: kop surat untuk semua halaman

Bayangkan kamu menulis 20 surat resmi. Setiap surat isinya berbeda, tapi bagian atasnya selalu sama: logo perusahaan, alamat kantor, dan tanggal. Kamu tentu tidak mengetik ulang kop itu 20 kali, kamu memakai template kop surat, lalu hanya menulis isi yang berbeda.

Layout di Next.js adalah "kop surat" untuk halaman web. Header, navbar, sidebar, dan footer yang tampil di banyak halaman cukup ditulis sekali di layout.tsx, lalu setiap page.tsx otomatis terbungkus di dalamnya tanpa perlu import manual.

Kenapa konsep ini ada?

Tanpa layout, setiap halaman harus me-render header dan footer sendiri. Akibatnya:

  • Duplikasi: kode navbar yang sama disalin ke 20 file. Satu perubahan desain berarti mengedit 20 file satu per satu.
  • Navigasi terasa berat: karena header ikut di-render ulang setiap pindah halaman, navigasi kehilangan keuntungan client-side yang cepat.
  • Inkonsistensi: lama-lama ada halaman yang navbarnya beda versi karena lupa diupdate saat desain berubah.

Layout menyelesaikan ini dengan satu prinsip kuat: UI yang tidak berubah dipertahankan saat navigasi. Next.js me-cache layout dan tidak me-render ulangnya ketika kamu pindah antar halaman dalam segmen yang sama, sehingga hanya konten halaman yang berganti.

Contoh 1: root layout (wajib ada)

Setiap project App Router wajib punya app/layout.tsx. Ini layout paling luar yang membungkus seluruh aplikasi, dan satu-satunya tempat yang boleh me-render tag <html> dan <body>:

tsx
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="id">
      <body>
        <header>
          <nav>Brand | Beranda | Tentang</nav>
        </header>
        <main>{children}</main>
        <footer>© 2026 TokoKu</footer>
      </body>
    </html>
  );
}

children adalah prop spesial: Next.js mengisinya otomatis dengan halaman (atau layout di bawahnya) yang sedang aktif. Kamu tidak pernah mengisi children secara manual, cukup sediakan slot-nya.

Contoh 2: nested layout khusus satu section

Layout bisa ditaruh di subfolder, dan ia hanya membungkus route di dalam folder itu:

app/ ├── layout.tsx # header/footer global untuk semua halaman └── blog/ ├── layout.tsx # sidebar khusus blog ├── page.tsx → /blog └── [slug]/page.tsx → /blog/apa-saja
tsx
// app/blog/layout.tsx
export default function BlogLayout({ children }: { children: React.ReactNode }) {
  return (
    <div className="flex">
      <aside className="w-64">
        <h2>Blog</h2>
        <ul>
          <li>Tutorial</li>
          <li>Berita</li>
          <li>Opini</li>
        </ul>
      </aside>
      <section className="flex-1">{children}</section>
    </div>
  );
}

Hasilnya berlapis: root layout membungkus blog layout, blog layout membungkus page. Saat pengguna pindah dari /blog ke /blog/hello, root layout dan blog layout tidak di-render ulang, hanya page yang berganti. Sidebar blog tetap di tempatnya, dan state di dalamnya (misalnya kategori yang sedang dipilih) tidak hilang.

Layout juga boleh async, sehingga bisa fetch data yang jarang berubah, misalnya daftar kategori dari database, sekali saja untuk seluruh section. Data itu diambil sekali dan dipakai ulang selama pengguna menjelajah section tersebut.

Kesalahan umum pemula

1. Lupa tag <html> dan <body> di root layout

Salah:

tsx
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <div>
      <header>Brand</header>
      {children}
    </div>
  );
}

Next.js membutuhkan <html> dan <body> dari root layout untuk membangun dokumen HTML yang valid. Tanpa keduanya, aplikasi error atau metadata seperti judul tab tidak terpasang dengan benar.

Benar:

tsx
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="id">
      <body>
        <header>Brand</header>
        {children}
      </body>
    </html>
  );
}

Catatan penting: tag <html> dan <body> hanya boleh ada di root layout. Nested layout tidak boleh me-render keduanya lagi, cukup me-return elemen biasa seperti <div>.

2. Menaruh data spesifik halaman di dalam layout

Salah: fetch detail artikel di app/blog/layout.tsx, padahal setiap artikel butuh data yang berbeda.

Layout di-cache dan tidak di-render ulang saat navigasi dalam segmennya, jadi data spesifik halaman yang ditaruh di layout akan basi (stale) atau tercampur antar halaman. Aturannya sederhana: data yang sama untuk semua halaman di section itu (daftar kategori, info user yang login) taruh di layout, data yang berbeda per halaman (isi artikel, detail produk) taruh di page.

3. Membuat lebih dari satu root layout

Hanya boleh ada satu root layout di app/layout.tsx. Kalau butuh tampilan yang sangat berbeda untuk satu section (misalnya halaman login tanpa navbar sama sekali), jangan membuat root layout kedua. Pakai route group (auth) dengan layoutnya sendiri, atau buat layout yang sudah ada menjadi kondisional.

Ringkasan: layout adalah UI bersama yang ditulis sekali dan dipakai banyak halaman. Root layout wajib ada dan memegang <html> beserta <body>. Nested layout membungkus satu section dan di-cache saat navigasi, jadi taruh data yang jarang berubah di sana, bukan data yang spesifik per halaman.

Tantangan

Layout blog

Buat app/blog/layout.tsx berisi judul "Blog" + daftar kategori di sidebar. Buat 2 halaman blog dan pastikan keduanya memakai layout yang sama.