In this section

Theme markers

A marker is one line in a theme file that Tovu fills with real content: the header, a menu, the page body, your latest posts. This page lists every marker type and key, with the HTML each one renders.

A marker is an ordinary HTML element with a data-embed-config attribute. Tovu finds it and fills it in, or swaps it out, with real content. One attribute, JSON inside, single quotes outside:

<nav class="main-nav" data-embed-config='{"type":"menu","id":"menu-header-nav"}'>…</nav>

Rules that apply to every marker:

  • type is required. It says what goes here.
  • Most types also take an id: which menu, which partial, which item.
  • Wrap the JSON in single quotes, so the JSON's own double quotes need no escaping.
  • Fallback content: whatever you put inside the marker shows when there is nothing to fill it with, such as a menu that doesn't exist yet. Put sensible links there, not "loading…".
  • Markers inside <!-- comments -->, <script>, or <style> are ignored. Commenting a marker out really does turn it off.
  • A marker needs a closing tag. <div data-embed-config='…' /> is not a marker.

Every marker type

typeWhat it puts thereKeysFills or replaces?
partialA shared file from render/partials/id, current, variantReplaces the marker
menuA menu you edit in Admin → Menusid, variantFills the marker, keeps its tag
contentThe body of the page or post being viewedid, slug, headerFills the marker
post-previewsA list of your latest postslimitFills the marker
collectionEntries from a collectionid, where, sort, limit, columns, layout, fieldsFills the marker
widgetA widgetid or slugSee Embeds
mediaAn image, video, or fileid or slug, variant (size)See Embeds
postAnother post, inlineid or slugSee Embeds

widget, media, post, and collection also work inside page bodies. The Embeds and Collections pages cover them in full.

<div data-embed-config='{"type":"partial","id":"nav","current":"docs"}'></div>
  • id: which partial. theme.json's slots maps each id to a file (see theme.json). Without a slots block, nav and footer map to nav.html and footer.html.
  • current (optional): marks one link in the partial as the current page. It finds <a href="…" data-nav-id="docs"> in the partial and adds aria-current="page". Write the link with href first and data-nav-id second, and nothing after, or it won't match. Once a real menu fills the nav, the menu marks the current page itself, so current only affects the partial's fallback links.
  • variant (optional): use a different version of the partial. "variant":"minimal" loads the file slots names for it, or footer-minimal.html by convention.

Before and after:

<!-- page source -->
<div data-embed-config='{"type":"partial","id":"footer","variant":"minimal"}'></div>

<!-- rendered: the marker is gone, the partial is in its place -->
<footer class="site-footer">…</footer>   (contents of footer-minimal.html)

If you give the marker any other attribute (a class, say), the element stays and wraps the partial. An id that slots doesn't know leaves the marker untouched.

<nav class="main-nav" data-embed-config='{"type":"menu","id":"menu-header-nav"}'>
  <a href="/docs">Docs</a>
</nav>
  • id: the menu's slug or id, as shown in Admin → Menus.
  • variant (optional): "tree" renders nested items. Leave it out for a flat row of links.

The marker's own tag and attributes stay (<nav class="main-nav"> survives). Only what's inside changes. Deleted or unpublished targets are left out, never shown as dead links.

Flat (default). Top-level items only, as bare links. Child items are not shown at all.

<nav class="main-nav" data-embed-config='{"type":"menu","id":"menu-footer-nav"}'><a href="/docs">Docs</a><a href="/about" aria-current="page">About</a></nav>

Tree. Add "variant":"tree" to get every level, as nested lists, with classes to style against:

<nav class="docs-nav" data-embed-config='{"type":"menu","id":"docs-section","variant":"tree"}'>
  <ul class="menu-list depth-0">
    <li class="menu-item depth-0 has-children is-active">
      <a href="/docs#get-started">Get started</a>
      <ul class="menu-list depth-1">
        <li class="menu-item depth-1 is-current is-active"><a href="/quickstart" aria-current="page">Your first site</a></li>
      </ul>
    </li>
  </ul>
</nav>
ClassMeans
menu-list depth-NA <ul> at nesting level N (0 = top)
menu-item depth-NAn <li> at level N
has-childrenThis item has a submenu
is-currentThis item is the page being viewed
is-activeThis item or something under it is the page being viewed. Use it to open the right section.
your own classWhatever you typed in the menu item's CSS class field

Why tree isn't the default: most nav CSS styles nav > a. A tree wraps links in <ul><li>, so switching an existing nav to tree breaks its layout until you add CSS for the lists. Opt in one marker at a time. A menu item with a description or icon gets <span class="menu-item-desc"> / <span class="menu-item-icon" data-icon="…"> in tree mode.

Built-in docs menus. Three menu ids don't name a stored menu. They are computed from your header menu's Docs item, the top-level item that links to /docs:

idRenders
docs-sectionThe Docs item's groups and pages, as a tree. For a docs sidebar.
docs-prev-nextThe previous and next docs page, tagged docs-pager-prev / docs-pager-next.
docs-current-page-sidebarOlder convention: a menu with slug docs-<page-slug>-sidebar. Still works.

Add a docs page to the Docs item in Admin → Menus, and the sidebar and pager pick it up.

content: the page or post being viewed

<article class="post-detail">
  <div data-embed-config='{"type":"content"}'></div>
</article>
  • No id: the page or post at the current URL. This is what every template uses.
  • id or slug: show a different page or post here instead.
  • header (optional): false hides the title and date header Tovu adds to posts written in the editor. Use it on landing pages. Only the JSON value false works, not the string "false".

A template (see theme.json) must contain at least one content marker.

post-previews: latest posts

<section class="blog-grid" data-embed-config='{"type":"post-previews","limit":6}'>
  <p>No posts yet.</p>
</section>
  • limit (optional): how many. Default 6, max 24.

Renders one card per post, newest first:

<article class="post-card"><h3><a href="/hello">Hello</a></h3><div class="post-meta"><time datetime="2026-09-03T…">Sep 3, 2026</time></div></article>

With no published posts, your fallback content stays.

See also: Embeds for markers inside page bodies, and Create a theme.