Now that we’ve seen components, we could use them directly to create the pages that make up our website.
For example, if our website had two pages, home and contact, we could create a component index.astro and contacto.astro.
In the next entry, we’ll see how to route each page to its component, and how to do it better if we had many, many pages.
But for now, let’s go this way. One page, one component.
But we would have a problem: we are repeating code. In both files, we have the <!DOCTYPE html>, the <html>, the <head>, the <meta> tags, the body.
If tomorrow we want to change the website’s title, add a Google Font, or install Google Analytics, are you going to go file by file editing the <head>?
To solve this, Astro uses Layouts (templates).
What is a Layout in Astro?
A Layout in Astro is nothing more than a normal, ordinary component. There is no special file type.
It’s simply a .astro file that uses the <slot /> tag (which we saw in the previous lesson) to wrap the content of a page.
By simple convention, we save these components in the src/layouts/ folder. And that’s it, nothing more (it seems silly but they are useful).
Creating our base Layout
Let’s see it with an example. Let’s create the file Layout.astro. This file will be the “skeleton” or “wrapper” for all pages on our site.
---
interface Props {
title: string;
description?: string;
}
const { title, description = "Welcome to my website made with Astro" } = Astro.props;
---
<!doctype html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<meta name="description" content={description} />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
</head>
<body>
<slot />
</body>
</html>
<style is:global>
/* Global styles for the entire website */
html {
font-family: system-ui, sans-serif;
background: #13151a;
color: white;
}
body {
margin: 0;
padding: 0;
}
</style>
Let’s analyze what we’ve done:
- We defined Props: The layout accepts a
titleand adescriptionso that each page has its own SEO. - HTML Structure: We’ve centralized all the HTML boilerplate.
- The
<slot />: This is the key. Everything we write inside our pages will be injected right where we placed this tag, inside the<body>. - Global Styles: We used
<style is:global>. This applies CSS to the entire website (perfect for resets or base fonts).
Using the Layout on a page
Now, let’s see how we would use the layout concept to make our home page index.astro. Let’s remove all the repetitive HTML and contain it in a Layout.
---
import Layout from '../layouts/Layout.astro';
import Boton from '../components/Boton.astro';
---
<Layout title="Home | My Astro Website">
<main>
<h1>Welcome to the future</h1>
<p>This page is wrapped in a Layout.</p>
<Boton texto="Learn more" />
</main>
</Layout>
Look how clean! Our index.astro file now only cares about the content, not the document setup.
If we go to contacto.astro, we’ll do the same:
---
import Layout from '../layouts/Layout.astro';
---
<Layout title="Contact" description="Get in touch with us">
<h1>Contact form</h1>
</Layout>
Composite Layouts (Header and Footer)
A Layout is usually not just empty HTML. Normally we want all pages to have the same Navigation Menu (Header) and the same Footer.
The ideal is to create components for these pieces and integrate them into the Layout.
Suppose we have src/components/Header.astro and src/components/Footer.astro. We update our Layout:
---
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
interface Props {
title: string;
}
const { title } = Astro.props;
---
<!doctype html>
<html lang="es">
<head>
<title>{title}</title>
</head>
<body>
<Header />
<main class="contenido-principal">
<slot />
</main>
<Footer />
</body>
</html>
Now, with a single change in Header.astro, the menu updates on all 500 pages of your website.
Layouts for Markdown
Astro has a great feature for those who write a lot of content in Markdown (like this page you are reading).
We can specify which Layout a .md file should use directly in its frontmatter (the Markdown one, not the Astro one).
---
layout: ../../layouts/BlogLayout.astro
title: "My first post"
author: "Luis Llamas"
---
Here I write in normal Markdown. Astro will take this content
and inject it into the <slot /> of BlogLayout.
The BlogLayout.astro component will automatically receive all the variables from the frontmatter (title, author, etc.) inside the frontmatter prop.
---
// src/layouts/BlogLayout.astro
const { frontmatter } = Astro.props;
---
<html lang="es">
<h1>{frontmatter.title}</h1>
<p>Written by: {frontmatter.author}</p>
<article>
<slot /> </article>
</html>
Nesting Layouts
A slightly more advanced technique is that we can also nest layouts. That is, use one Layout as a template for another Layout.
Why? Imagine you have LayoutBase.astro (with the HTML and SEO). But for some pages you want a design with a sidebar, and for the rest of the website you don’t.
You can create a SidebarLayout.astro that uses LayoutBase.astro:
---
import LayoutBase from './LayoutBase.astro';
const { title } = Astro.props;
---
<LayoutBase title={title}>
<div class="pantalla-dividida">
<aside>I am the blog sidebar</aside>
<main>
<slot />
</main>
</div>
</LayoutBase>
This way you would have:
- A
LayoutBasewith the minimal structure common to the entire website - A
Layout...for each type of page you have (with sidebar, with two sidebars, etc.)
