static_

Components

Any .vue file in components/ is available everywhere by its PascalCase name: components/price-card.vue or PriceCard.vue becomes <PriceCard />. No imports needed.

<script setup>
defineProps({ title: String, items: { type: Array, default: () => [] } });
</script>

<template>
    <section>
        <h2>{{ title }}</h2>
        <slot />
        <li v-for="item in items" :key="item.id">{{ item.name }}</li>
        <slot name="footer" />
    </section>
</template>
<PriceCard title="Pro" :items="data.plans">
    Body goes in the default slot.
    <template #footer>Named slot</template>
</PriceCard>

This is plain Vue 3 (v-if, v-for, :prop, slots, <script setup>, computed, imports) rendered once at build time. Nothing is hydrated in the browser. Scaffold one with static add component price-card.

Unknown components and undefined template variables fail the build with the file and component named. Don't ignore them.

Globals in every template

name what
site data/site.json
data every other data/*.json, as data.<filename>
env only PUBLIC_* environment variables
page current page (title, url, canonical, description, post)
navigation nav items with url and isActive
collections collections.posts etc., arrays of entries
currentYear, dev the year, and true under static dev
tagUrl(collection, tag) URL of a tag page
frontmatter keys everything in the page's frontmatter; the data page as variable too

In <script setup>, get them with:

import { useStatic } from '@static';
const { site, data, page } = useStatic();

Browser JavaScript

<script setup> only runs at build time. For code that runs in the browser (a lightbox, a menu toggle) add a separate <script client> block to a component or page. It is minified and emitted once per page, and only on pages where the component rendered:

<template><button id="menuBtn">Menu</button></template>

<script client>
document.getElementById('menuBtn').addEventListener('click', () => { /* ... */ });
</script>

Built-in components

A project component with the same name overrides a built-in.

component use
<Image src="hero.jpg" alt="..." sizes="..." priority /> <picture> with AVIF/WebP srcset, width and height, lazy loading, for files in images/ and note media
<Icon name="PieChart" class="size-6" /> inline Lucide icon, PascalCase or kebab-case
<ThemeToggle /> dark/light switch; the theme is applied before first paint
<Lightbox :images="[...]" alt="Name" noun="screenshot" /> scrolling thumbnails and a full-screen viewer (arrow keys, Esc)
<NoteImages :images="post.images" /> the image grid used by notes
<BlogPost />, <BlogList /> default layouts for collection entries and listings

The built-ins live in the CLI (lib/builtins/components/). To customise one, create a project component with the same name, optionally starting from a copy of the original.