Page Layouts
WordPress has “Page Templates” — a dropdown in the editor that lets you pick a layout per page (e.g. Default, Full Width, Landing Page). EmDash supports the same pattern using a select field.
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
No special system is needed — this uses EmDash’s existing 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 (e.g. “Default”, “Full Width”). Or include it in your seed data:
{ "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 } from "emdash";import { PortableText } from "emdash/ui";import Base from "./Base.astro";
interface Props { page: ContentEntry<any>;}
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 } from "emdash";import { PortableText } from "emdash/ui";import Base from "./Base.astro";
interface Props { page: ContentEntry<any>;}
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 { getEmDashEntry } from "emdash";import PageDefault from "../../layouts/PageDefault.astro";import PageFullWidth from "../../layouts/PageFullWidth.astro";
const { slug } = Astro.params;
if (!slug) { return Astro.redirect("/404");}
const { entry: page } = await getEmDashEntry("pages", slug);
if (!page) { return Astro.redirect("/404");}
const layouts = { "Default": PageDefault, "Full Width": PageFullWidth,};
const Layout = layouts[page.data.template as keyof typeof layouts] ?? 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 choices from WordPress themes:
- 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 sidebar widget area
Each is just another Astro component in your src/layouts/ directory and another entry in the route’s layout map.