Cara Membuat Sistem Layout Reusable pada Astro JS Themes dengan Slots dan Props
Membangun Astro JS Themes yang terlihat konsisten bukan sekadar menyalin header dan footer ke setiap halaman. Theme yang siap dipakai ulang membutuhkan sistem layout yang jelas: data halaman masuk melalui Props, markup fleksibel masuk melalui Slots, dan variasi halaman dibentuk lewat komposisi komponen. Dengan pola ini, satu fondasi dapat melayani landing page, katalog produk, artikel, dokumentasi, serta halaman kontak tanpa menghasilkan banyak file yang hampir sama.
Pendekatan reusable layout juga berdampak langsung pada kualitas project. Perubahan navigasi cukup dilakukan sekali, metadata SEO memiliki sumber yang konsisten, dan developer baru dapat memahami batas tanggung jawab setiap file. Pada Astro, keuntungan tersebut diperoleh tanpa menambahkan runtime JavaScript secara otomatis karena komponen .astro dirender menjadi HTML pada build time atau saat request diproses server.
Panduan ini membahas cara merancang reusable layout Astro secara bertahap, mulai dari default slot, named slots Astro, typed props, nested layout, hingga contoh arsitektur theme nyata. Contoh menggunakan praktik Astro modern dan TypeScript agar dapat dijadikan fondasi project produksi, bukan hanya demo singkat.
Mengapa Astro JS Themes Membutuhkan Sistem Layout Reusable?
Sebuah theme biasanya mempunyai elemen global seperti dokumen HTML, metadata, navigasi, footer, container, warna, dan tipografi. Di atas fondasi tersebut terdapat pola yang lebih spesifik: blog memiliki informasi penulis, produk memiliki galeri dan CTA, sedangkan landing page membutuhkan hero serta social proof. Jika semua kebutuhan dimasukkan ke satu file layout besar, setiap penambahan fitur akan memperbesar risiko regresi.
Sistem reusable memisahkan tiga lapisan. Base layout menangani struktur dokumen dan kebutuhan global. Section layout menangani pola berdasarkan tipe halaman, misalnya BlogLayout atau ProductLayout. Page hanya mengirim data dan konten unik. Pembagian ini membuat Astro theme development lebih mudah diuji dan dirawat.
Manfaat untuk konsistensi dan maintainability
- Metadata dasar, canonical, font, header, dan footer memiliki satu sumber.
- Perubahan desain global tidak perlu diterapkan pada puluhan halaman.
- Props bertipe mendokumentasikan konfigurasi yang didukung layout.
- Slots menjaga konten halaman tetap fleksibel tanpa menyalin shell UI.
- Layout khusus dapat berkembang tanpa membuat base layout mengetahui semua fitur.
Tujuan akhirnya bukan membuat abstraksi sebanyak mungkin. Layout reusable yang baik justru memiliki API kecil, mudah ditebak, dan stabil. Setiap prop atau slot harus menjawab kebutuhan nyata pada lebih dari satu halaman atau menjadi batas arsitektur yang memang penting.
Memahami Perbedaan Astro Slots dan Astro Props
Slots dan Props sama-sama mengirim sesuatu ke komponen, tetapi bentuk serta tanggung jawabnya berbeda. Astro Props membawa data melalui atribut komponen dan tersedia pada Astro.props. Contohnya adalah title, description, theme, daftar navigasi, atau flag untuk menampilkan sidebar. Astro Slots membawa markup anak ke placeholder <slot /> di dalam template.
Gunakan prop ketika layout perlu mengambil keputusan berdasarkan nilai. Gunakan slot ketika pemanggil perlu menentukan struktur HTML yang akan dirender pada lokasi tertentu. Judul halaman biasanya prop karena juga dipakai untuk elemen <title>. Konten artikel lebih tepat menjadi default slot karena terdiri dari heading, paragraf, gambar, dan komponen lain.
Aturan praktis memilih Props atau Slots
- Pilih prop untuk string, angka, boolean, object konfigurasi, dan array data.
- Pilih slot untuk markup yang komposisinya berbeda antarhalaman.
- Pilih named slot untuk area markup dengan posisi semantik yang tetap.
- Jangan mengirim HTML sebagai string prop jika dapat dikirim sebagai slot.
- Jangan membuat slot hanya untuk mengganti satu label sederhana.
Struktur Folder Astro Theme yang Mudah Dikembangkan
Astro tidak mewajibkan layout disimpan di folder tertentu, tetapi konvensi yang konsisten membantu tim. Struktur berikut memisahkan shell global, layout domain, komponen, dan halaman:
src/
components/
Header.astro
Footer.astro
SeoHead.astro
ProductCard.astro
layouts/
BaseLayout.astro
MarketingLayout.astro
BlogLayout.astro
ProductLayout.astro
pages/
index.astro
blog/[slug].astro
products/[slug].astro
styles/
global.css
BaseLayout.astro sebaiknya tidak mengetahui detail rating produk atau profil penulis. Detail tersebut menjadi tanggung jawab ProductLayout dan BlogLayout. Batas ini mencegah base layout berubah menjadi komponen serbaguna yang sulit dipahami.
Membuat BaseLayout dengan Typed Props dan Default Slot
Mulailah dari kontrak props yang kecil. TypeScript membantu mendeteksi title yang hilang atau variant yang salah sebelum build berhasil. Nilai opsional dapat memperoleh default ketika Astro.props didestrukturisasi.
---
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
import '../styles/global.css';
interface Props {
title: string;
description?: string;
lang?: 'id' | 'en';
bodyClass?: string;
}
const {
title,
description = 'Website modern berbasis Astro',
lang = 'id',
bodyClass = '',
} = Astro.props;
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
---
<!doctype html>
<html lang={lang}>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonicalURL} />
<slot name="head" />
</head>
<body class={bodyClass}>
<Header />
<main><slot /></main>
<Footer />
</body>
</html>
Default slot pada elemen <main> menerima seluruh child yang tidak memiliki nama slot. Slot head memberi jalan bagi halaman untuk menambahkan metadata khusus tanpa menduplikasi semua elemen global.
Menggunakan layout dari halaman
---
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout
title="Katalog Astro Themes"
description="Koleksi theme Astro untuk project modern."
>
<meta slot="head" property="og:type" content="website" />
<section>
<h1>Astro Themes</h1>
<p>Pilih fondasi yang sesuai untuk project Anda.</p>
</section>
</BaseLayout>
Halaman hanya menentukan data dan konten yang unik. Struktur dokumen tetap dikelola BaseLayout sehingga tidak ada perbedaan metadata viewport, bahasa, atau urutan elemen global antarhalaman.
Menerapkan Named Slots Astro untuk Area yang Fleksibel
Default slot cukup untuk konten utama, tetapi theme sering mempunyai area opsional seperti hero, breadcrumb, sidebar, action, atau metadata tambahan. Named slot mendefinisikan lokasi tersebut secara eksplisit.
---
interface Props {
title: string;
eyebrow?: string;
}
const { title, eyebrow } = Astro.props;
const hasSidebar = Astro.slots.has('sidebar');
---
<section class="page-hero">
{eyebrow && <p class="eyebrow">{eyebrow}</p>}
<h1>{title}</h1>
<slot name="hero-actions" />
</section>
<div class:list={['content-grid', { 'has-sidebar': hasSidebar }]}>
<article><slot /></article>
{hasSidebar && <aside><slot name="sidebar" /></aside>}
</div>
Astro.slots.has('sidebar') memungkinkan layout mengubah grid hanya jika sidebar benar-benar diberikan. Ini lebih bersih dibanding merender kolom kosong. Dokumentasi Astro juga menjelaskan bahwa fallback slot muncul ketika tidak ada child yang cocok.
Mengirim beberapa elemen melalui Fragment
Named slot harus diterapkan pada child langsung dari komponen. Jika satu slot perlu menerima beberapa elemen tanpa wrapper tambahan, gunakan <Fragment>:
<MarketingLayout title="Theme untuk SaaS">
<Fragment slot="hero-actions">
<a href="/demo">Lihat Demo</a>
<a href="/products">Lihat Produk</a>
</Fragment>
<p>Konten utama halaman masuk ke default slot.</p>
<Fragment slot="sidebar">
<h2>Dalam paket</h2>
<ul><li>Layout reusable</li><li>Komponen SEO</li></ul>
</Fragment>
</MarketingLayout>
Kesalahan yang sering terjadi adalah meletakkan elemen berslot di dalam <div> biasa. Named slots harus menjadi child langsung agar Astro dapat memasukkannya ke placeholder yang benar.
Passing Props yang Aman pada Astro Layout Components
Props adalah API layout. Karena itu, nama dan tipe props sebaiknya stabil, spesifik, serta tidak saling bertentangan. Hindari rangkaian boolean seperti showHero, smallHero, darkHero, dan centerHero. Sebuah union prop lebih mudah dipahami.
---
interface Props {
title: string;
variant?: 'default' | 'editorial' | 'product';
theme?: 'light' | 'dark' | 'system';
container?: 'narrow' | 'wide' | 'full';
}
const {
title,
variant = 'default',
theme = 'system',
container = 'wide',
} = Astro.props;
---
<div
data-variant={variant}
data-theme={theme}
class:list={['layout-shell', 'container-' + container]}
>
<h1>{title}</h1>
<slot />
</div>
Default value menjaga penggunaan sederhana tetap singkat, sedangkan union type membatasi konfigurasi ke pilihan yang memang didukung desain. Untuk object kompleks, definisikan interface terpisah agar kontrak mudah digunakan ulang.
Jangan menyebarkan semua props tanpa kontrol
Spread props dapat berguna untuk meneruskan atribut HTML, tetapi jangan meneruskan seluruh Astro.props ke elemen DOM. Data internal dapat berubah menjadi atribut yang tidak valid atau bahkan membocorkan nilai yang tidak ditujukan untuk markup. Pisahkan atribut layout dari atribut HTML yang memang diizinkan.
Membangun Nested Layout untuk Theme Nyata
Nested layout memungkinkan satu layout khusus memakai fondasi layout lain. Misalnya BaseLayout mengelola dokumen, ProductLayout mengelola breadcrumb serta struktur produk, lalu halaman detail hanya mengirim data produk.
---
// src/layouts/ProductLayout.astro
import BaseLayout from './BaseLayout.astro';
interface Props {
title: string;
description: string;
priceLabel?: string;
}
const { title, description, priceLabel } = Astro.props;
---
<BaseLayout title={title} description={description} bodyClass="product-page">
<slot name="head" slot="head" />
<header class="product-hero">
<p>Astro Theme</p>
<h1>{title}</h1>
{priceLabel && <strong>{priceLabel}</strong>}
<slot name="actions" />
</header>
<div class="product-content">
<slot />
</div>
</BaseLayout>
Baris <slot name="head" slot="head" /> meneruskan slot head dari ProductLayout ke BaseLayout. Atribut name menyatakan slot yang diterima, sedangkan atribut slot menyatakan tujuan pada komponen induk. Pola transfer ini berguna untuk metadata Product, Article, atau Breadcrumb structured data.
Contoh halaman produk yang ringkas
---
import ProductLayout from '../../layouts/ProductLayout.astro';
import FeatureGrid from '../../components/FeatureGrid.astro';
const product = await getProduct(Astro.params.slug);
---
<ProductLayout
title={product.title}
description={product.excerpt}
priceLabel={product.priceLabel}
>
<script slot="head" type="application/ld+json"
set:html={JSON.stringify(product.schema)} />
<a slot="actions" href={product.checkoutUrl}>Beli Theme</a>
<p>{product.description}</p>
<FeatureGrid items={product.features} />
</ProductLayout>
Pada project nyata, URL checkout harus tervalidasi di server dan structured data harus dibangun dari data resmi. Layout hanya menyediakan lokasi dan presentasi; aturan bisnis tetap berada pada service atau page loader.
Contoh Arsitektur Astro Theme Development
Bayangkan theme marketplace dengan empat tipe halaman. Homepage memakai MarketingLayout, daftar produk memakai CatalogLayout, detail memakai ProductLayout, dan artikel memakai BlogLayout. Keempatnya membungkus BaseLayout yang sama. Header, footer, consent script, analytics, dan metadata global tidak perlu diulang.
MarketingLayout menyediakan slot hero dan social-proof. CatalogLayout menerima props filter serta default slot untuk grid. ProductLayout menyediakan actions dan head. BlogLayout menerima author, tanggal pembaruan, serta slot related-content. Setiap layout mempunyai tanggung jawab domain yang jelas.
Saat brand mengubah footer atau canonical policy, BaseLayout menjadi satu-satunya tempat yang disentuh. Saat card pembelian berubah, ProductLayout atau komponen produk yang diperbarui. Ini merupakan contoh maintainability yang nyata, bukan sekadar pengurangan jumlah baris kode.
Optimasi Performa Layout Astro
Reusable layout tidak otomatis cepat jika diisi script berat. Kekuatan Astro berasal dari rendering HTML tanpa JavaScript client secara default. Pertahankan sifat tersebut dengan hanya melakukan hydration pada komponen interaktif. Header statis, breadcrumb, daftar fitur, dan footer biasanya tidak membutuhkan client:load.
Batasi hydration pada kebutuhan nyata
- Gunakan HTML dan CSS untuk navigasi atau disclosure sederhana jika memadai.
- Pilih
client:visibleuntuk widget bawah halaman yang baru dibutuhkan saat terlihat. - Jangan mengubah seluruh layout menjadi komponen framework hanya karena satu tombol interaktif.
- Hindari memasukkan library carousel atau animasi pada semua halaman lewat base layout.
Kelola asset dan font dari satu tempat
Base layout tepat untuk stylesheet global dan resource hint yang benar-benar digunakan semua halaman. Asset khusus artikel atau produk sebaiknya dimuat oleh layout domain atau halaman terkait. Memasukkan seluruh CSS dan font ke shell global membuat setiap route membayar biaya yang sama.
Untuk gambar hero, tetapkan dimensi atau aspect ratio agar layout tidak bergeser. Gunakan format modern dan ukuran responsif. Performa theme lebih banyak dipengaruhi keputusan asset, JavaScript, dan font daripada jumlah file layout.
Praktik Terbaik Reusable Layout Astro
- Mulai dari duplikasi nyata. Ekstrak pola setelah terlihat pada beberapa halaman, bukan berdasarkan kemungkinan yang belum ada.
- Buat kontrak props kecil. Props yang terlalu banyak menandakan layout menangani terlalu banyak tanggung jawab.
- Gunakan tipe yang bermakna. Union type lebih aman daripada string bebas untuk variant dan theme.
- Sediakan default yang masuk akal. Penggunaan paling umum harus membutuhkan konfigurasi paling sedikit.
- Gunakan named slot secara semantik. Nama seperti
head,sidebar, danactionslebih jelas daripadatopatauarea2. - Pisahkan UI dan data. Query database dan otorisasi sensitif sebaiknya tidak tersebar di layout presentasional.
- Jaga aksesibilitas. Layout harus mempertahankan landmark, urutan heading, skip link, fokus keyboard, dan bahasa dokumen.
- Uji variasi penting. Periksa layout dengan atau tanpa sidebar, judul panjang, konten kosong, serta viewport mobile.
Kesalahan Umum yang Perlu Dihindari
Satu layout untuk seluruh kemungkinan
Layout dengan puluhan props dan kondisi bercabang sulit diprediksi. Pecah menjadi base layout dan layout domain. Komposisi lebih sehat daripada satu komponen yang memahami semua halaman.
Named slot bukan child langsung
Astro mengharuskan elemen dengan atribut slot menjadi child langsung dari komponen penerima. Gunakan Fragment jika perlu mengirim beberapa elemen, bukan membungkusnya dengan div yang berada satu tingkat lebih dalam.
Menggandakan title dan metadata
Jika page dan layout sama-sama merender <title>, output dapat memiliki metadata ganda. Tetapkan pemilik metadata global, lalu sediakan named slot head hanya untuk tambahan yang spesifik.
Menggunakan Props untuk HTML mentah
HTML string mempersulit sanitasi dan type checking. Gunakan slot untuk markup tepercaya. Untuk konten dari CMS, lakukan sanitasi pada boundary yang tepat dan jangan menganggap layout sebagai lapisan keamanan utama.
Hydration global tanpa kebutuhan
Menambahkan directive client pada wrapper besar dapat menghilangkan keuntungan zero-JS. Isolasi interaktivitas pada komponen kecil dan ukur dampaknya melalui build output serta Core Web Vitals.
Checklist Sebelum Astro JS Themes Dirilis
- Semua layout memiliki Props interface dan default yang tepat.
- Hanya satu title, description, dan canonical yang dirender per halaman.
- Named slots diuji dalam kondisi terisi dan kosong.
- Layout bertingkat meneruskan slot head ke tujuan yang benar.
- Tidak ada data sensitif yang diteruskan ke atribut HTML.
- Heading dan landmark tetap logis pada semua template.
- JavaScript client hanya dimuat untuk komponen interaktif.
- Gambar mempunyai dimensi, alt text, dan format yang efisien.
- Build, type check, link internal, dan tampilan mobile telah diuji.
Kesimpulan
Sistem layout reusable pada Astro JS Themes dibangun melalui pembagian tanggung jawab yang disiplin. Props membawa data dan konfigurasi, Slots membawa markup, named slots menentukan area khusus, dan nested layout menyusun template domain di atas shell global. Kombinasi ini menghasilkan theme yang fleksibel tanpa mengorbankan kejelasan API.
Mulailah dari BaseLayout yang kecil, tambahkan layout domain ketika pola halaman benar-benar berbeda, dan pertahankan JavaScript client hanya pada area yang membutuhkan interaksi. Dengan struktur tersebut, Astro layout components tetap cepat, mudah diuji, dan nyaman dikembangkan saat jumlah halaman maupun anggota tim bertambah.
Untuk memperdalam fondasi arsitektur Astro, baca juga panduan Astro Islands untuk website ringan, panduan Astro 6 dan Content Layer API, serta tutorial landing page Astro dan Tailwind CSS. Ketiganya melengkapi pembahasan layout dengan strategi interaktivitas, konten, dan implementasi halaman produksi.
FAQ
Apa fungsi slot pada layout Astro?
Slot menjadi placeholder tempat halaman atau komponen induk memasukkan markup ke layout. Default slot cocok untuk konten utama, sedangkan named slots cocok untuk area khusus seperti hero, sidebar, head, atau action.
Apa perbedaan Astro Slots dan Astro Props?
Props membawa data terstruktur seperti judul, deskripsi, variant, atau konfigurasi. Slots membawa markup atau kumpulan elemen HTML. Keduanya saling melengkapi untuk membangun layout reusable.
Apakah props pada komponen Astro dapat menggunakan TypeScript?
Ya. Komponen Astro dapat mendefinisikan interface Props di frontmatter. Astro menggunakan interface tersebut untuk membantu type checking dan autocomplete saat props dipakai.
Kapan named slots sebaiknya digunakan pada Astro JS Themes?
Gunakan named slots ketika layout memiliki area markup opsional yang posisinya jelas, misalnya head, hero, sidebar, breadcrumb, atau action. Hindari membuat terlalu banyak slot untuk variasi kecil yang lebih tepat direpresentasikan sebagai props.
Bisakah layout Astro disusun secara bertingkat?
Bisa. Layout khusus seperti ProductLayout atau BlogLayout dapat membungkus BaseLayout. Props dan slot tertentu dapat diteruskan ke layout induk sehingga struktur global tetap konsisten.
Apakah reusable layout menambah JavaScript di browser?
Tidak secara otomatis. Komponen dan layout Astro dirender menjadi HTML pada build time atau server. JavaScript client hanya dikirim jika developer menambahkan script atau komponen interaktif dengan client directive.
Apa kesalahan paling umum saat membuat layout Astro theme?
Kesalahan umum meliputi layout monolitik, props tanpa tipe, named slot yang bukan child langsung, duplikasi metadata SEO, terlalu banyak boolean props, dan menambahkan hydration pada bagian yang sebenarnya statis.


