Templates
React Templates
1 min read
Templates are React components that receive a PageContext and return JSX.
Basic template
// theme/templates/post.tsx
import type { StedefastTemplate } from "/renderer";
export const layout = "default"; // use theme/layouts/default.tsx
const PostTemplate: StedefastTemplate = ({ page, site }) => {
const fm = page.frontMatter as { title: string; date?: Date };
return (
<article>
<h1>{fm.title}</h1>
{fm.date && <time>{fm.date.toLocaleDateString()}</time>}
<div dangerouslySetInnerHTML={{ __html: page.content }} />
</article>
);
};
export default PostTemplate;
PageContext
Every template receives a PageContext object:
interface PageContext {
page: {
slug: string;
url: string;
type: string;
frontMatter: Record<string, unknown>;
content: string; // pre-rendered HTML
excerpt?: string;
readingTimeMinutes?: number;
};
site: {
title: string;
description?: string;
baseUrl: string;
nav: ContentNode[]; // showInNav pages, sorted by order
};
allContent: ContentGraph; // full content index
modules: ModulePageData; // dynamic module data
listing?: ListingPage; // only present on listing pages
}
Template resolution
For a content node with type: "post" and slug: "my-article", Stedefast looks for:
theme/templates/my-article.tsx— exact slug matchtheme/templates/post.tsx— type match (first found)theme/templates/default.tsx— fallback
Override the template per-page with template: "custom-name" in front matter.
Layouts
Layouts wrap templates with shared chrome (navigation, footer, <html> shell).
// theme/layouts/default.tsx
import type { StedefastLayout } from "/renderer";
const DefaultLayout: StedefastLayout = ({ site, children }) => (
<html lang="en">
<head>
<title>{site.title}</title>
<link rel="stylesheet" href="/assets/main.css" />
</head>
<body>
<header><a href="/">{site.title}</a></header>
<main>{children}</main>
</body>
</html>
);
export default DefaultLayout;
Declare the layout in your template:
export const layout = "default"; // looks for theme/layouts/default.tsx