Templates
This page covers the conventions for writing pages and partials under src/. It walks through how page data flows, how the layout property picks a parent, and how layout chaining is composed.
Passing page data with YAML frontmatter
MDX templates declare their Eleventy page data in a YAML block fenced by --- at the very top of the file — the same shape you would expect from any Markdown frontmatter.
---
layout: post
title: My first site
description: The first page built with the boilerplate
---
# My first site
The body starts here.
Any value expressible as YAML scalars, mappings, or sequences goes in as-is. layout is required under the preset, and title / description are read by many partials (like ogp.mdx).
Behind the scenes the MDX processor (Sätteri) is only responsible for detecting the leading --- fence and extracting the frontmatter block; the YAML inside is parsed by this plugin (via the yaml package). The parsed result is handed to Eleventy's 11ty.js template as export const data = ..., so pages read exactly like any other Eleventy frontmatter-driven page.
.jsx / .tsx templates cannot use --- fences because of JSX parsing rules, so they keep the export const data = { ... } form. MDX files may also use export const data, but combining it with frontmatter in the same file is rejected as a duplicate export — pick one.
Selecting a parent with layout
Each page names its parent layout in the layout field. The value is a path relative to _includes/, without the extension.
---
layout: post # uses src/_includes/post.mdx
---
Parent layouts can carry their own layout, so layouts chain multiple levels deep.
Composing layout chains
The scaffold defaults to a three-level chain:
src/index.mdx → src/_includes/post.mdx → src/_includes/base.mdx
(page) (article wrapper) (HTML skeleton)
Each layout receives the child's rendered HTML on eleventy.content and injects it with dangerouslySetInnerHTML, so the child's output slots into the parent's JSX tree.
Root layout (_includes/base.mdx)
Owns the full HTML skeleton: <html>, <head>, <body>, and the <main> where child content goes.
import { eleventy } from "@tuqulore-inc/eleventy-preset/eleventy";
<html lang={eleventy.locale ?? "ja"}>
<head>
<title>
{eleventy.title && `${eleventy.title} | `}
{eleventy.site.name}
</title>
<link rel="stylesheet" href="/main.css" />
</head>
<body>
<main dangerouslySetInnerHTML={{ __html: eleventy.content }} />
</body>
</html>
Intermediate layout (_includes/post.mdx)
Owns a content wrapper (<article class="prose"> and so on) and picks base as its parent.
---
layout: base
---
import { eleventy } from "@tuqulore-inc/eleventy-preset/eleventy";
<article class="prose" dangerouslySetInnerHTML={{ __html: eleventy.content }} />
Where the split usually falls
- Keep a single root layout so the
<html>skeleton is not duplicated. - Add intermediate layouts per page type (
postfor articles,listfor index pages, and so on). - Have pages target intermediate layouts, not the root — the chain stays maintainable that way.
Slotting partials in
MDX and JSX partials under _includes/partials/ are imported and used as JSX inside layouts.
import Header from "./partials/header.mdx";
import Footer from "./partials/footer.mdx";
<Header />
<main dangerouslySetInnerHTML={{ __html: eleventy.content }} />
<Footer />
Partials read the values they need from their own props and from the eleventy singleton, described in Data Access. Layouts do not have to drill props down to them.
Slotting Islands in
Anything you want to hydrate on the client goes under src/**/*.client.jsx and is embedded from MDX via <Island>.
import { Island } from "@tuqulore-inc/eleventy-preset/island";
import Counter from "./counter.client.jsx";
<Island component={Counter} on="interaction" initial={5} />
The design of <Island> and guidance on granularity live in Plugins / eleventy-plugin-preact-island.