Components
All components are registered globally by enhanceApp() and are available in any Markdown page or Vue template without explicit imports. Composables must be imported explicitly from their source paths.
TypeScript-typed props give inline documentation in VS Code (Volar extension) and JetBrains IDEs — hover a prop in a template to see its description.
<ScavoldMenu>
Renders a <nav> element containing a nested list of page links derived from the site's page hierarchy. Nothing is rendered when the resolved item set is empty.
The component has three independent addressing modes — path-based, absolute (from root), and relative (from current page) — that cover all common navigation patterns without requiring knowledge of the current page's depth.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
from-path | string | — | Select the parent node by path. Supports {locale} (full BCP 47 tag, e.g. de-CH) and {lang} (primary language subtag only, e.g. de) placeholders, replaced with the current page's locale at runtime. Takes priority over from-root and from. Examples: "de/footer", "{lang}/footer". |
from-root | number | — | List items at this absolute depth from root. 1 = top-level pages, 2 = second level, etc. Ignored when from-path is set. |
from | number | 0 | List items relative to the current page. 0 = siblings, 1 = children, -1 = aunt/uncle level. Ignored when from-root or from-path is set. |
depth | number | 0 | Additional levels to descend below the starting level. 0 = flat list, 1 = one level of children, -1 = unlimited. |
active-only | boolean | false | Only expand children along the branch leading to the current page. |
expand | boolean | false | Expand children of all nodes regardless of active branch. active-only takes precedence. |
label | string | — | aria-label for the <nav> landmark. Required when more than one <ScavoldMenu> appears on the same page. |
Rendered markup
<nav aria-label="…">
<ul>
<li class="active"> <!-- .active: current page or an ancestor -->
<a href="/section/">Section</a>
<ul>
<li class="active current"> <!-- .current: exactly the current page -->
<a href="/section/page/" aria-current="page">Page</a>
</li>
</ul>
</li>
</ul>
</nav>Label resolution
Menu item labels are resolved in this order:
labelfrontmatter — explicit navigation texttitlefrontmatter — page title- First
#heading extracted at build time - Last path segment (e.g.
aboutfromde/about.md)
Hiding pages
Set hide: menu (or hide: true) in a page's frontmatter to exclude it from menus. The page is still served and still appears in the hierarchy tree.
Examples
<!-- top-level pages — typical site header nav -->
<ScavoldMenu :from-root="1" label="Main navigation" />
<!-- second level of active section only -->
<ScavoldMenu :from-root="2" active-only />
<!-- children of the current page -->
<ScavoldMenu :from="1" />
<!-- siblings of the current page -->
<ScavoldMenu />
<!-- full site hierarchy (sitemap) -->
<ScavoldMenu :from-root="1" :depth="-1" />
<!-- locale-aware footer nav — works with path structures de/, en/, etc. -->
<ScavoldMenu from-path="{lang}/footer" label="Footer navigation" /><ScavoldBreadcrumb>
Renders a <nav class="breadcrumb"> element with a flat list of links from root to the current page. Uses the same <ul>/<li>/<a> structure as <ScavoldMenu> so both can share CSS rules.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
include-current | boolean | true | Include the current page as the final crumb. |
include-root | boolean | false | Include the root node as the first crumb. |
Rendered markup
<nav class="breadcrumb">
<ul>
<li class="active"><a href="/de/">Deutsch</a></li>
<li class="active current"><a href="/de/leistungen/">Leistungen</a></li>
</ul>
</nav>Examples
<!-- typical usage -->
<ScavoldBreadcrumb />
<!-- without current page, when the page heading serves as the final crumb -->
<ScavoldBreadcrumb :include-current="false" />
<!-- full trail including home link -->
<ScavoldBreadcrumb include-root /><ScavoldLocaleMenu>
Renders a <nav class="locale-nav"> element listing links to the available translations of the current page. Nothing is rendered when the resolved link set is empty or (by default) when only a single locale is available.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
detection | "auto" | "explicit" | "inherited" | "global" | "auto" | How to discover available locales. See Detection modes. |
include-current | boolean | false | Include the current locale as a non-navigating item. |
hide-if-single | boolean | true | Render nothing when only one (or zero) locale links are available. |
label | string | "Language" | aria-label for the <nav> landmark. |
Detection modes
| Mode | Description |
|---|---|
"auto" | Tries explicit, then inherited, then global; uses the first mode that yields at least one link. |
"explicit" | Only locales declared in the current page's own translations frontmatter. |
"inherited" | For each locale, links to the translation declared by the nearest ancestor with a translations entry. Section-level declarations cover all child pages that have no direct counterpart. |
"global" | Every locale present anywhere in the hierarchy. Links to the topmost page in that locale. |
Rendered markup
<nav class="locale-nav" aria-label="Language">
<ul>
<li class="current" lang="de">
<span aria-current="true">de</span>
</li>
<li lang="en">
<a href="/en/" hreflang="en" aria-label="en">en</a>
</li>
</ul>
</nav>Examples
<!-- show locales from current page or nearest ancestor with translations -->
<ScavoldLocaleMenu />
<!-- always show all known locales; link to their topmost page -->
<ScavoldLocaleMenu detection="global" />
<!-- show all locales including current, even when only one is listed -->
<ScavoldLocaleMenu detection="global" include-current :hide-if-single="false" /><ScavoldLayout>
Base layout wrapper that intercepts pages with locale-conditional redirect frontmatter and renders <ScavoldLocaleRedirect> in their place. All other pages render the default slot.
Wrap your site shell in this component to inherit redirect handling automatically:
<template>
<ScavoldLayout>
<div class="site-shell">
<!-- header, nav, main, footer … -->
</div>
</ScavoldLayout>
</template>Themes that need finer control can compose the building blocks directly using useRedirect() and <ScavoldLocaleRedirect>:
<script setup>
import { useRedirect } from "scavold/composables/useRedirect.js";
import ScavoldLocaleRedirect from "scavold/components/ScavoldLocaleRedirect.vue";
const { isLocaleRedirect } = useRedirect();
</script>
<template>
<ScavoldLocaleRedirect v-if="isLocaleRedirect" />
<div v-else class="site-shell">…</div>
</template><ScavoldPageList>
Links a configurable number of the site's own pages — the latest posts of a blog, a teaser row of a section's sub-pages, a list of downloads. Rendered for the :::pagelist container block; anything written inside the block is rendered above the list.
Titles, dates, introductory texts and teaser images all come from the target pages, so authors maintain them where the content lives.
::: pagelist from=1 limit=5 sort=date teaser images dates heading-level=3 label="Recent posts"
## Recent posts
:::Arguments
| Argument | Type | Default | Description |
|---|---|---|---|
from | number | 1 | Level relative to the current page: 1 = its sub-pages, 0 = its siblings. |
from-root | number | — | Absolute level from the site root. Takes precedence over from. |
from-path | string | — | Path of the page whose sub-pages are listed, with {locale} / {lang} support. Takes precedence over both other selectors. |
deep | flag | — | Include every level below, flattened into one list. |
limit | number | 5, or 0 with per-page | Maximum number of entries; 0 lists all of them. A paginated list reaches every page it found unless a limit says otherwise. |
offset | number | 0 | Entries to skip at the start. |
sort | "order" | "date" | "date-asc" | "title" | "order" | order follows the site structure, date is newest first. |
reverse | flag | — | Reverse the selected order. |
teaser | flag | — | Show each page's introductory text. |
images | flag | — | Show each page's teaser image. |
dates | flag | — | Show each page's date. |
date-style | "short" | "medium" | "long" | "full" | "iso" | "long" | Style of the dates. The Intl.DateTimeFormat styles follow the page's language; iso writes 2020-10-20 in every language. |
time-style | "short" | "medium" | "long" | "full" | "iso" | — | Style of the time of day. Left out, entries show their date only. iso writes 12:16. |
timezone | string | "UTC" | IANA name of the zone the dates are read in, e.g. Europe/Berlin. |
heading-level | number | 0 | Heading level of the titles; 0 renders a plain list of links. |
image-sizes | string | "(min-width: 60rem) 30rem, 90vw" | CSS sizes descriptor for the teaser images. |
label | string | — | Accessible label (aria-label) for the list. |
per-page | number | 0 | Entries per page; 0 shows all. Paging happens in the browser and adds a pager. |
param | string | "page" | Query parameter the current page is remembered in, for pages carrying several paginated lists. |
The data per entry is read from title, date, excerpt and image of the target page, with the page body as the fallback for the last two. A page opts out with hide: list.
Rendered markup
<div class="scavold-pagelist">
<!-- slot content -->
<ul class="scavold-pagelist__items" aria-label="Recent posts">
<li class="scavold-pagelist__item">
<a class="scavold-pagelist__link" href="/blog/newest">
<picture class="scavold-pagelist__image">…</picture>
<h3 class="scavold-pagelist__title">Newest post</h3>
<time class="scavold-pagelist__date" datetime="2026-06-21T00:00:00.000Z">21 June 2026</time>
<p class="scavold-pagelist__excerpt">Opening prose of the post…</p>
</a>
</li>
</ul>
</div>One link per entry, with the teaser image decorative inside it, so a screen reader announces each entry once. The component ships no CSS; the classes above are the theme's hooks.
per-page pages the list in the browser: only the current page's entries are rendered, the page shown is remembered as ?page=2 through history.replaceState, and the pager is a labelled <nav> with a status line and buttons. The pre-rendered HTML always holds page one, so a shared ?page=3 link shows it for an instant, and entries beyond page one are not in the HTML for a crawler to find — the sitemap and the feed are.
<ScavoldImage>
Renders a <picture> element with full srcset and sizes support. Scavold inserts this component automatically in place of every local <img> processed during the build — you typically do not use it directly in templates.
Site-specific layout components that need to control the sizes value for a particular context should pass it explicitly:
<ScavoldImage src="/photo.jpg" alt="A photo" sizes="(min-width: 60rem) 50vw, 100vw" />Props
| Prop | Type | Default | Description |
|---|---|---|---|
src | string | — | Image path, resolved against media_folder. |
alt | string | "" | Alt text. Empty string marks the image as decorative (role="presentation"). |
title | string | — | Caption or title text. |
sizes | string | site default | CSS sizes descriptor for the <source> element. Overrides the site-level image_sizes default. |
widths | number[] | site default | Explicit list of variant widths. Overrides the site-level image_widths default. |
<ScavoldVideo>
Container component for embedded video. Accepts all options via the useVideo composable.
Props
See videoProps from scavold/composables/useVideo.js for the full list. Common props:
| Prop | Type | Description |
|---|---|---|
src | string | Video source URL or path. |
poster | string | Poster image path. |
autoplay | boolean | Autoplay the video (muted). |
loop | boolean | Loop the video. |
Sectioning wrappers
Seven thin wrapper components map to their corresponding HTML sectioning elements. They exist primarily to serve as Markdown container targets so that :::section, :::aside, etc. produce the correct element with the container arguments wired as props.
| Component | Element |
|---|---|
<ScavoldSection> | <section> |
<ScavoldAside> | <aside> |
<ScavoldArticle> | <article> |
<ScavoldHeader> | <header> |
<ScavoldFooter> | <footer> |
<ScavoldNav> | <nav> |
<ScavoldMain> | <main> |
Each accepts containerProps (see useContainer below) and any additional props or slots specific to its element type.
<ScavoldContainer>
Fallback used for any container name that has no registered component. Renders as the matching HTML sectioning element if the name is one of the seven above, otherwise as a <div>. Adds the container name to the element's class list.
Composables
useHierarchy()
import { useHierarchy } from "scavold/composables/hierarchy";
const { hierarchy, current } = useHierarchy();| Return value | Type | Description |
|---|---|---|
hierarchy | Ref<HierarchyNode> | The full page tree root. |
current | Ref<HierarchyNode> | The node for the page currently being viewed. |
HierarchyNode properties:
| Property | Type | Description |
|---|---|---|
path | string | Path of the Markdown source file. |
isPage | boolean | Whether this node represents an actual page. |
title | string? | Display title (frontmatter or first heading). |
label | string? | Navigation label (frontmatter label, falls back to title). |
url | string? | Alias output path when url is declared in frontmatter. |
locale | string? | Inherited locale (BCP 47) — see locale. |
excerpt | string? | Introductory text — excerpt or the page's opening prose. |
image | string? | Lead image reference — image or the first image in the page. |
imageData | object? | Responsive variant data (src, srcset, webpSrcset) for image, resolved at build time. |
date | string? | Publication date as an ISO 8601 timestamp — see date. |
frontmatter | object? | Full frontmatter data for this page. |
parent | HierarchyNode? | Parent node (non-enumerable, not serialised). |
subs | object? | Child nodes keyed by path segment, sorted by order. |
useContainer() / containerProps
Used inside custom container components to consume the arguments parsed from the opening ::: line. Container names and their argument declarations are configured in .cratly.config.yaml → containers.
import { useContainer, containerProps } from "scavold/composables/useContainer.js";
const props = defineProps( {
...containerProps,
background: String, // custom KV arg: background=/media/hero.jpg
} );
const { containerName, classes, dataAttrs } = useContainer( props );useContainer return values:
| Value | Type | Description |
|---|---|---|
containerName | string | The container name (e.g. "hero"). |
classes | string[] | Flag arguments as class names. |
dataAttrs | object | Key–value arguments as data-* attributes. |
containerProps:
| Prop | Type | Description |
|---|---|---|
containerArgs | string | Raw argument string from the ::: opening line. |
usePageList() / pageListProps
Used inside custom page-list components to turn the arguments of a :::pagelist block into ready-to-render entries — the same selection, ordering and formatting <ScavoldPageList> uses.
import { usePageList, pageListProps } from "scavold/composables/usePageList.js";
const props = defineProps( pageListProps );
const { items, headingTag, teaser, images, dates, imageSizes, ariaLabel, formatDate } =
usePageList( props );| Return value | Type | Description |
|---|---|---|
items | Ref<PageListItem[]> | Entries with node, href, title, date, excerpt and image resolved. |
headingTag | Ref<string | null> | Heading element for the titles, null for a plain list of links. |
teaser / images / dates | Ref<boolean> | Whether the respective flag is set. |
imageSizes | Ref<string> | CSS sizes descriptor for the teaser images. |
ariaLabel | Ref<string | undefined> | Accessible label for the list. |
formatDate | (iso: string) => string | Formats a timestamp in the page's locale, in UTC. |
useRedirect()
import { useRedirect } from "scavold/composables/useRedirect.js";
const { isLocaleRedirect, redirect } = useRedirect();| Return value | Type | Description |
|---|---|---|
isLocaleRedirect | Ref<boolean> | true when the current page has a locale-conditional redirect in frontmatter. |
redirect | Ref<object | string> | The raw redirect frontmatter value. |
useVideo() / videoProps
Used inside custom video container components.
import { useVideo, videoProps } from "scavold/composables/useVideo.js";
const props = defineProps( videoProps );
const { attrs } = useVideo( props );