This episode builds the Astro UI foundation: creating pages in src/pages, reusable layouts with slots in src/layouts, Astro components with props and frontmatter, the difference between framework components, and styling with global CSS, scoped styles, and Tailwind.

After the project is ready from episode 3, it is time to build the main building blocks of the site: pages, layouts, and components. These three are the UI foundation of Astro — almost everything you build in this series comes down to these three concepts.
Pages define routes, layouts wrap many pages with a shared skeleton, and components are reusable pieces of UI. Combining them with tidy styling produces a site that is consistent and easy to maintain.
Episode 4 is full practice: you will create your first page, a reusable layout, components with props, and then try styling with plain CSS, scoped styles, and Tailwind.
Every .astro file in src/pages becomes a route. Create src/pages/tentang.astro for the /tentang page:
---
const namaSitus = "Astro Learn";
---
<html lang="id">
<head>
<title>Tentang Kami</title>
</head>
<body>
<h1>Halo, selamat datang di {namaSitus}</h1>
<p>Halaman ini dirender sebagai HTML murni saat build.</p>
</body>
</html>Frontmatter (between ---) contains JavaScript that runs at build time. The value of {namaSitus} is interpolated into the template — you will use this interpolation pattern over and over.
For dynamic pages like article detail pages, use brackets in the file name:
---
export function getStaticPaths() {
return [
{ params: { slug: "satu" } },
{ params: { slug: "dua" } },
];
}
const { slug } = Astro.params;
---
<h1>Artikel: {slug}</h1>getStaticPaths produces the list of static pages to be built — each item in the array becomes one HTML file in dist/.
A layout is a special component that wraps page content. Create src/layouts/Base.astro:
---
interface Props {
title: string;
}
const { title } = Astro.props;
---
<html lang="id">
<head>
<title>{title}</title>
</head>
<body>
<nav>Logo | Beranda | Blog | Kontak</nav>
<main>
<slot />
</main>
<footer>Hak cipta 2026</footer>
</body>
</html>The <slot /> element is a marker where the page content will be inserted. Props are received through Astro.props and declared with interface Props.
Use the layout by importing and wrapping the page:
---
import Base from "../layouts/Base.astro";
---
<Base title="Beranda">
<h1>Beranda</h1>
<p>Konten halaman masuk ke slot layout.</p>
</Base>A layout saves a lot of duplicated code — the title, meta tags, navigation, and footer only need to be written once.
.astro components are pieces of UI without page-level HTML. Example src/components/Card.astro:
---
interface Props {
judul: string;
deskripsi: string;
}
const { judul, deskripsi } = Astro.props;
---
<article class="card">
<h2>{judul}</h2>
<p>{deskripsi}</p>
</article>This component can be used anywhere with <Card judul="Astro" deskripsi="Cepat" />. The --- fence above the script defines the boundary between frontmatter logic and the HTML template.
React, Vue, Svelte, and Solid components can also be used in .astro files. The difference: those components are interactive and need a hydration directive for their JavaScript to be shipped. Astro components themselves do not need a directive — they are always rendered as static HTML unless used as an island with a directive.
Global CSS goes in src/styles and is imported in layouts. For styles that only apply to one component, Astro provides scoped styles:
<style>
.card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 1rem;
}
</style>Astro automatically adds a unique hash to the selectors in a <style> block, so .card will not leak into other components.
Tailwind can be enabled with a single integration command:
npx astro add tailwindnpx astro add tailwind installs the package and configures Vite. After that, utility classes can be used directly across all templates, including inside .astro files and framework components.
Tip
The most common combination: the layout holds global CSS and meta tags, small components use scoped styles or Tailwind utility classes, and pages simply assemble everything.
Episode 4 builds the three UI foundations of Astro: pages in src/pages in static and dynamic modes, reusable layouts with slots, Astro components with props, and styling through global CSS, scoped styles, and Tailwind.
The key takeaways:
src/pages becomes a route, static or dynamic.getStaticPaths determines the list of dynamic pages at build time.<slot /> and accept props like title.<style> blocks in components are automatically scoped.npx astro add tailwind enables Tailwind in a single command.In the next episode 5, we will cover content and markdown: writing content with Markdown and MDX, leveraging content collections with schemas, frontmatter and metadata, and rendering dynamic content on static pages. This is the heart of a content-driven site.