Page Layouts
Let editors pick a layout per page, for example Default, Full Width, or Landing Page. A select field stores the choice, and the page route maps that value to an Astro layout component.
How it works
Section titled “How it works”- Add a
templateselect field to your pages collection - Create layout components for each option
- Map the field value to a layout in your page route
This uses EmDash’s select field and Astro’s component model.
Add the field
Section titled “Add the field”In the admin UI, add a select field to your pages collection with slug template and your layout options (for example, “Default” and “Full Width”). To define the same field in seed data, add the following object to the collection’s fields array:
{ "slug": "template", "label": "Template", "type": "select", "validation": { "options": ["Default", "Full Width"] }, "defaultValue": "Default"}Create layout components
Section titled “Create layout components”Each layout wraps content in your base layout with different styling:
---import type { ContentEntry, InferCollectionData } from "emdash";import { PortableText } from "emdash/ui";import Base from "./Base.astro";
interface Props { page: ContentEntry<InferCollectionData<"pages">>;}
const { page } = Astro.props;---
<Base title={page.data.title}> <article class="page-default"> <h1>{page.data.title}</h1> <PortableText value={page.data.content} /> </article></Base>
<style> .page-default { max-width: var(--content-width); margin: 0 auto; padding: 2rem 1rem; }</style>---import type { ContentEntry, InferCollectionData } from "emdash";import { PortableText } from "emdash/ui";import Base from "./Base.astro";
interface Props { page: ContentEntry<InferCollectionData<"pages">>;}
const { page } = Astro.props;---
<Base title={page.data.title}> <article class="page-wide"> <h1>{page.data.title}</h1> <PortableText value={page.data.content} /> </article></Base>
<style> .page-wide { max-width: var(--wide-width); margin: 0 auto; padding: 2rem 1rem; }</style>Wire up the route
Section titled “Wire up the route”In your page route, import each layout and map the template value:
---import { decodeSlug, getEmDashEntry } from "emdash";import PageDefault from "../../layouts/PageDefault.astro";import PageFullWidth from "../../layouts/PageFullWidth.astro";
const slug = decodeSlug(Astro.params.slug);
if (!slug) { return Astro.redirect("/404");}
const { entry: page } = await getEmDashEntry("pages", slug);
if (!page) { return Astro.redirect("/404");}
const layouts = new Map([ ["Default", PageDefault], ["Full Width", PageFullWidth],]);
const Layout = layouts.get(page.data.template ?? "") ?? PageDefault;---
<Layout page={page} />The route stays small. Each layout component owns its own markup and styling. Adding a layout is: create a component, add the option to the select field, add a line to the map.
Adding more layouts
Section titled “Adding more layouts”Common layout choices:
- Default — narrow content column, good for reading
- Full Width — wider content area, no sidebar
- Landing Page — no header/footer, hero sections
- Sidebar — content with a widget area beside it
Each is just another Astro component in your src/layouts/ directory and another entry in the route’s layout map.