Templates
Pongo page templates and supporting files live in templates/. Veta does not prescribe subdirectories inside it, so each project can organize layouts, fragments, and macro libraries as needed. A page object uses a template by setting template:
export default function({ parse }) {
const { html } = parse.markdown("# Welcome");
return [
{
permalink: "/",
template: "base",
title: "Home",
content: html,
},
];
}
Veta resolves the name relative to templates/. It passes the generator's content string unchanged and trusted to the template; Markdown rendering and component resolution are explicit generator operations.
Template Names
Veta supports any template extension, but .j2 is the recommended convention for Pongo templates and components. Pongo uses Jinja-style syntax, and many editors and formatters already recognize .j2 files well.
templates/base.j2
templates/navigation.j2
components/card.j2
You can include the file extension:
template: "base.j2";
Or omit it:
template: "base";
When the extension is omitted, Veta scans for a non-ignored file with the same stem. For example, base can resolve to templates/base.j2.
If more than one file matches the same extensionless name, Veta reports an ambiguous template error.
Template Context
Templates receive exactly these root keys:
data
pages
page
props
Example:
<title>{{ page.title }} - {{ data.site.name }}</title>
{% for item in pages %}
<a href="{{ item.permalink }}">{{ item.title }}</a>
{% endfor %}
<main>{{ page.content }}</main>
props is usually empty in page templates. It is populated when rendering components.
Inheritance
Pongo inheritance works inside templates/:
{# templates/base.j2 #}
<!DOCTYPE html>
<html lang="en">
<head>
<title>{% block title %}{{ data.site.name }}{% endblock %}</title>
</head>
<body>
{% block main %}{% endblock %}
</body>
</html>
{# templates/pages/article.j2 #}
{% extends "../base.j2" %}
{% block title %}
{{ page.title }} | {{ block.Super }}
{% endblock %}
{% block main %}
<article>{{ page.content }}</article>
{% endblock %}
Use ./ or ../ for relative paths in extends and include statements.
Includes
Pongo templates can include other files by project-relative path:
{% include "templates/brand.html" %}
Includes receive the current template context, including data, pages, page, and props.
Use with to provide values explicitly and only to isolate an included file from the current context:
{% include "templates/user-card.j2" with user=page.author only %}
Page templates and components use the same loader, so both can reuse files under templates/.
Macros And Imports
Macros define callable template fragments. Add export when a macro must be imported from another file:
{# templates/ui.j2 #}
{% macro button(text, href, tone="primary") export %}
<a class="button button-{{ tone }}" href="{{ href }}">{{ text }}</a>
{% endmacro %}
Import the exported names that the caller needs. Imports can use aliases:
{% import "templates/ui.j2" button as action %}
{{ action("Read the guide", "/guides/") }}
Macros can also be defined and called in the same file without export. Macro files use the normal template loader, including extensionless names and project-over-theme overrides.
Loading Data
Pongo templates and components can load local or remote data with load_data:
{% set navigation = load_data("data/navigation.yaml")|parse_yaml %}
{% set site = load_data("data/site.json")|parse_json %}
Use load_data for template-specific data. Use global data/ files for data shared across the whole site. See Template Functions for the full API.
Functions
Pongo templates and components can call built-in functions such as url, regex_replace, and load_data. Projects can add custom JavaScript functions in functions/:
// functions/excerpt.js
export default function({ page }, value, length) {
return String(value || page.title).slice(0, Number(length));
}
{{ excerpt(page.content, 120) }}
See Template Functions for details.
Filters
Veta registers built-in filters and custom filters:
<script type="application/json">
{{ page|json }}
</script>
{{ page.summary|markdown }}
Custom JavaScript filters live in filters/ and are documented in Filters.
Ignored Template Files
Veta ignores template files or path segments that:
- start with
. - end with
~ - end with
.tmp
This lets editors keep temporary files in the project without affecting builds.