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:

# {frontmatter.title ?? ctx.page.title}

Current route: {ctx.routePath}

Context Shape

Common fields on ctx:

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:

Note: directory index routes include a trailing slash in routePath (e.g. /guide/).

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:

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.