Overview
Layouts in Astro are components that wrap page content and provide consistent structure across the site. Chapinismos uses a single base layout that handles HTML structure, meta tags, and global elements.
Base Layout
The Base.astro layout is the foundation for all pages.
File Location
Full Layout Structure
---
import "../styles/global.css" ;
import Header from "../components/Header.astro" ;
import Footer from "../components/Footer.astro" ;
import { ClientRouter } from "astro:transitions" ;
import OrganizationSchema from "../components/schemas/OrganizationSchema.astro" ;
import WebsiteSchema from "../components/schemas/WebsiteSchema.astro" ;
const {
title = "Chapinismos" ,
description = "Glosario de chapinismos guatemaltecos" ,
keywords = "chapinismos, diccionario guatemalteco" ,
ogImage = "/og-image.svg" ,
canonicalUrl = Astro . url . pathname ,
type = "website" ,
lang = "es" ,
alternateUrls = {},
} = Astro . props ;
const siteUrl = Astro . site || "https://chapinismos.org" ;
const fullCanonicalUrl = new URL ( canonicalUrl , siteUrl ). toString ();
const fullOgImage = new URL ( ogImage , siteUrl ). toString ();
const ogLocale = lang === "en" ? "en_US" : "es_GT" ;
const alternateOgLocale = lang === "en" ? "es_GT" : "en_US" ;
---
< ! doctype html >
< html lang = { lang } data-theme = "dark" >
< head >
< meta charset = "utf-8" />
< meta name = "viewport" content = "width=device-width, initial-scale=1" />
<!-- Primary Meta Tags -->
< title > { title } </ title >
< meta name = "title" content = { title } />
< meta name = "description" content = { description } />
< meta name = "keywords" content = { keywords } />
< link rel = "canonical" href = { fullCanonicalUrl } />
<!-- Hreflang tags for multilingual SEO -->
{ alternateUrls . es && (
< link rel = "alternate" hreflang = "es" href = {new URL ( alternateUrls . es , siteUrl ). toString () } />
) }
{ alternateUrls . en && (
< link rel = "alternate" hreflang = "en" href = {new URL ( alternateUrls . en , siteUrl ). toString () } />
) }
<!-- Open Graph / Facebook -->
< meta property = "og:type" content = { type } />
< meta property = "og:url" content = { fullCanonicalUrl } />
< meta property = "og:title" content = { title } />
< meta property = "og:description" content = { description } />
< meta property = "og:image" content = { fullOgImage } />
< meta property = "og:locale" content = { ogLocale } />
<!-- Twitter -->
< meta property = "twitter:card" content = "summary_large_image" />
< meta property = "twitter:title" content = { title } />
< meta property = "twitter:description" content = { description } />
< meta property = "twitter:image" content = { fullOgImage } />
<!-- Favicon -->
< link rel = "icon" type = "image/svg+xml" href = "/favicon.svg" />
< link rel = "manifest" href = "/site.webmanifest" />
<!-- JSON-LD Structured Data -->
< OrganizationSchema lang = { lang } siteUrl = { siteUrl } />
< WebsiteSchema lang = { lang } siteUrl = { siteUrl } />
< slot name = "schema" />
<!-- View Transitions -->
< ClientRouter fallback = "none" />
</ head >
< body >
< Header />
< main id = "main-content" role = "main" >
< slot />
</ main >
< Footer />
</ body >
</ html >
Layout Props
The Base layout accepts the following props:
Prop Type Default Description titlestring ”Chapinismos” Page title (shown in browser tab) descriptionstring Default description Meta description for SEO keywordsstring Default keywords Meta keywords for SEO ogImagestring ”/og-image.svg” Open Graph image path canonicalUrlstring Current path Canonical URL for SEO typestring ”website” Open Graph type (website/article) langstring ”es” Page language (es/en) alternateUrlsobject Hreflang URLs for multilingual pages
Using the Layout
Basic Usage
src/pages/[lang]/index.astro
---
import Base from "../../layouts/Base.astro" ;
import { useTranslations } from "../../utils/i18n" ;
const { lang } = Astro . params ;
const t = useTranslations ( lang );
---
< Base
title = { t ( "home.title" ) }
description = { t ( "home.description" ) }
lang = { lang }
>
< h1 > Welcome to Chapinismos </ h1 >
< p > Content goes here... </ p >
</ Base >
With Alternate URLs (Multilingual)
src/pages/[lang]/palabras/[slug].astro
---
import Base from "../../../layouts/Base.astro" ;
const { lang , slug } = Astro . params ;
const alternateUrls = {
es: `/es/palabras/ ${ slug } /` ,
en: `/en/palabras/ ${ slug } /` ,
xDefault: `/es/palabras/ ${ slug } /` ,
};
---
< Base
title = "Word Title"
description = "Word description"
type = "article"
lang = { lang }
alternateUrls = { alternateUrls }
>
<!-- Page content -->
</ Base >
With Custom Schema
Use the schema slot to inject page-specific structured data:
---
import Base from "../layouts/Base.astro" ;
import BreadcrumbSchema from "../components/schemas/BreadcrumbSchema.astro" ;
import WordSchema from "../components/schemas/WordSchema.astro" ;
const { lang , slug } = Astro . params ;
const siteUrl = "https://chapinismos.org" ;
---
< Base title = "Page Title" lang = { lang } >
< BreadcrumbSchema
slot = "schema"
lang = { lang }
siteUrl = { siteUrl }
items = { [
{ name: "Index" , url: `/ ${ lang } /indice/` },
{ name: "Word" , url: `/ ${ lang } /palabras/ ${ slug } /` },
] }
/>
< WordSchema
slot = "schema"
lang = { lang }
siteUrl = { siteUrl }
word = { wordData }
slug = { slug }
/>
<!-- Page content -->
</ Base >
Layout Features
Head Management
Favicon and Icons
The layout includes multiple favicon formats:
< link rel = "icon" href = "/favicon-96x96.png" sizes = "96x96" />
< link rel = "icon" href = "/favicon-32x32.png" sizes = "32x32" />
< link rel = "icon" href = "/favicon-16x16.png" sizes = "16x16" />
< link rel = "icon" type = "image/svg+xml" href = "/favicon.svg" />
< link rel = "apple-touch-icon" href = "/apple-touch-icon.png" />
Structured Data (JSON-LD)
Every page includes base structured data:
Organization Schema
Website Schema
{
"@context" : "https://schema.org" ,
"@type" : "Organization" ,
"name" : "Diccionario Chapín" ,
"url" : "https://chapinismos.org" ,
"logo" : "https://chapinismos.org/favicon.svg"
}
{
"@context" : "https://schema.org" ,
"@type" : "WebSite" ,
"name" : "Chapinismos" ,
"url" : "https://chapinismos.org" ,
"potentialAction" : {
"@type" : "SearchAction" ,
"target" : "https://chapinismos.org/es/buscar/?q={search_term}"
}
}
Pages can add more schemas via the schema slot.
View Transitions
The layout includes Astro’s View Transitions for smooth page navigation:
< ClientRouter fallback = "none" />
Components can use transition:persist to maintain state across page transitions.
Global Styles
The layout imports global CSS:
import "../styles/global.css";
This includes:
CSS custom properties (theme variables)
Reset styles
Utility classes
Dark/light theme definitions
HTML Structure
<! doctype html >
< html lang = "{lang}" data-theme = "dark" >
< head >
<!-- Meta tags, links, scripts -->
</ head >
< body >
< Header / > <!-- Global header -->
< main role = "main" >
< slot / > <!-- Page content -->
</ main >
< Footer / > <!-- Global footer -->
</ body >
</ html >
Theme Attribute
The data-theme attribute controls dark/light mode:
< html data-theme = "dark" > <!-- Default -->
< html data-theme = "light" > <!-- User preference -->
This is toggled by the ThemeToggle component.
Preconnect to external origins
< link rel = "preconnect" href = "https://cloud.umami.is" />
< link rel = "dns-prefetch" href = "https://cloud.umami.is" />
< link rel = "preload" href = "/images/bg.webp" as = "image" fetchpriority = "low" />
< script async src = "https://cloud.umami.is/script.js" ></ script >
Configured in astro.config.mjs: build : {
inlineStylesheets : "always" ,
}
Creating Custom Layouts
You can create specialized layouts for different page types:
Create layout file
touch src/layouts/ArticleLayout.astro
Extend Base layout
---
import Base from "./Base.astro" ;
interface Props {
title : string ;
author : string ;
date : Date ;
lang : string ;
}
const { title , author , date , lang } = Astro . props ;
---
< Base title = { title } type = "article" lang = { lang } >
< article >
< header >
< h1 > { title } </ h1 >
< p > By { author } on { date . toLocaleDateString () } </ p >
</ header >
< slot />
</ article >
</ Base >
Use the new layout
---
import ArticleLayout from "../layouts/ArticleLayout.astro" ;
---
< ArticleLayout
title = "Article Title"
author = "John Doe"
date = {new Date () }
lang = "es"
>
< p > Article content... </ p >
</ ArticleLayout >
Best Practices
Always pass language prop
This ensures correct <html lang> attribute and locale-specific schemas.
< Base title = { ` ${ word . word } — ${ t ( "word.page.title" ) } ` } >
Include context in page titles for better SEO and user experience.
Provide alternate URLs for multilingual pages
const alternateUrls = {
es : `/es/page/` ,
en : `/en/page/` ,
xDefault : `/es/page/` ,
} ;
Use article type for content pages
< Base type = "article" lang = { lang } >
This provides better Open Graph metadata for word definitions.
Add page-specific schemas
< BreadcrumbSchema slot = "schema" ... />
< WordSchema slot = "schema" ... />
Next Steps
Styling Learn about global styles and theming
SEO Deep dive into SEO features
Components Explore reusable components
Internationalization Work with translations