Stedefast

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:

  1. theme/templates/my-article.tsx — exact slug match
  2. theme/templates/post.tsx — type match (first found)
  3. 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