MDX Runtime Helpers
Methanol injects a small runtime context into every MDX file to make templates and dynamic content easier to build.
Context Values
These helpers are always available:
ctx: page and site contextfrontmatter: shorthand forctx.page.frontmatterrawHTML: escape hatch for unescaped HTML
# {frontmatter.title ?? ctx.page.title}
Current route: {ctx.routePath}
Context Shape
Common fields on ctx:
ctx.page: current page metadata (see details below)ctx.pages: all pages (flat list; includes hidden and index pages)ctx.pagesTree: navigation tree for the current rootctx.site: site metadata (name,root,pagesDir,distDir,pagefind, etc.)ctx.withBase(path): prefixessite.base/Vite base for URLs that start with/(leaves relative URLs unchanged)ctx.language: active language entry (from directory index pages withlang; includeslabelandcode)ctx.getSiblings(): returns{ prev, next }for the current page within the current navigation root
Caveat: you usually don’t need ctx.withBase() for theme source URLs (theme.sources) or for static files under public/ (Methanol resolves those at build time). If you hit Vite dev inconsistencies (especially when generating URLs in JS), ctx.withBase('/...') can be a practical workaround.
ctx.page
ctx.page is the metadata object for the current page. Common fields include:
routePath: normalized route (e.g./guide/writing)routeHref: base-aware href for links (includessite.base/ Vite base)
Note: directory index routes include a trailing slash in routePath (e.g. /guide/).
filePath: absolute path to the source filetitle: resolved title (frontmatter title or derived from headings)frontmatter: parsed YAML frontmattertoc: extracted table of contents entriesisIndex:truewhen the file isindex.mdxdir: directory path relative topagesDirsegments: route segments arrayhidden: whether the page is hidden from navigationisRoot: whether the page marks a navigation rootdate: normalized ISO date when provided in frontmatterupdatedAt: last modified timestamp (when available)
Example usage:
{ctx.page.title}
{ctx.page.frontmatter?.excerpt}
ctx.pages
ctx.pages is a flat list of page objects (same shape as ctx.page) for all pages in the current project and theme. It includes index pages and pages that are hidden in navigation, but excludes pages marked exclude: true.
Use this when you need custom listings, sitemaps, or manual navigation:
<ul>
{ctx.pages.map((page) => (
<li><a href={page.routeHref || page.routePath}>{page.title}</a></li>
))}
</ul>
ctx.pagesTree
ctx.pagesTree is a hierarchical tree of navigation nodes for the current root (respecting isRoot and hidden rules). Nodes are shaped like:
type:"page"or"directory"title/name: label for displayroutePath/routeHref: route for the nodechildren: child nodes for directories
Use it to build a navigation UI that matches the sidebar:
{ctx.pagesTree.map((node) => (
<div>{node.title || node.name}</div>
))}
ctx.getSiblings
ctx.getSiblings() returns the previous and following pages in the current navigation sequence. It respects the current navigation root and hidden/excluded rules, so it mirrors the sidebar order.
{(() => {
const siblings = ctx.getSiblings()
if (!siblings) return null
return (
<nav>
{siblings.prev ? <a href={siblings.prev.routeHref || siblings.prev.routePath}>Previous: {siblings.prev.title}</a> : null}
{siblings.next ? <a href={siblings.next.routeHref || siblings.next.routePath}>Forward: {siblings.next.title}</a> : null}
</nav>
)
})()}
rawHTML
Use rawHTML to inject unescaped HTML. This is useful for inline scripts or markup that should not be escaped.
{rawHTML('<span class="badge">Beta</span>')}
{rawHTML`<div data-banner="true">Banner</div>`}
rawHTML also accepts signals and template interpolations.