Theming

DocAnvil's appearance is customizable through three layers, each building on the last:

  1. CSS variable overrides in docanvil.toml — quick color and font changes
  2. Custom CSS file — full control over any element
  3. Template overrides — replace the entire HTML layout with Tera templates

CSS Variables in Config

The simplest way to customize the theme. Add variables under [theme.variables] in docanvil.toml:

[theme.variables]
color-primary = "#059669"
color-primary-light = "#34d399"
color-link = "#059669"
color-link-hover = "#047857"

These are injected as a :root style block after the default theme, overriding the built-in values. Variable names omit the -- prefix — DocAnvil adds it automatically.

Custom CSS File

For more control, point custom_css to a stylesheet:

[theme]
custom_css = "theme/custom.css"

This file loads after both the default theme and config variable overrides, so it has the highest CSS specificity. Use it for:

Common Customizations

# docanvil.toml — change accent color and font
[theme.variables]
color-primary = "#059669"
color-primary-light = "#34d399"
color-link = "#059669"
font-body = "Georgia, serif"
/* theme/custom.css — wider content area with dark code blocks */
.content {
  max-width: 960px;
}

.content pre { background: #1e293b; color: #e2e8f0; border-color: #334155; }

.content pre code { color: inherit; }

Load Order

Styles are applied in this order (last wins):

  1. Default theme (style.css embedded in the binary)
  2. Config variables ([theme.variables]:root { ... })
  3. Custom CSS file (custom_css path)

Specificity

If a custom CSS rule doesn't seem to take effect, check that your selector is specific enough to override the default theme. Using .content pre is more specific than just pre.

Template Overrides

For complete control over the HTML structure, override the default Tera template. Create a file at theme/templates/layout.html in your project:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>{{ page_title }} — {{ project_name }}</title>
  <style>{{ default_css | safe }}</style>
  {% if css_overrides %}
  <style>:root { {{ css_overrides }} }</style>
  {% endif %}
  {% if custom_css_path %}
  <link rel="stylesheet" href="/{{ custom_css_path }}">
  {% endif %}
  {% block head %}{% endblock %}
</head>
<body>
  {% block sidebar %}
  <nav class="sidebar">
    <div class="project-name">{{ project_name }}</div>
    {{ nav_html | safe }}
  </nav>
  {% endblock %}

  <main class="content">
    {% block content %}
    {{ content | safe }}
    {% endblock %}

    {% block footer %}
    <div class="footer">
      Built with <a href="https://github.com/docanvil/docanvil">DocAnvil</a>
    </div>
    {% endblock %}
  </main>

  {% block scripts %}{% endblock %}
</body>
</html>

Template Blocks

Block Purpose
head Extra <head> content (fonts, meta tags, analytics)
sidebar The navigation sidebar
content Main page content area
footer Footer below content
scripts JavaScript at end of body

Template Variables

Variable Type Description
page_title String Title of the current page
project_name String Project name from docanvil.toml
default_css String The full default stylesheet (use with safe filter)
css_overrides String CSS variable overrides from config
custom_css_path String Path to custom CSS file, if configured
nav_html String Rendered navigation HTML (use with safe filter)
content String Rendered page HTML (use with safe filter)
live_reload Boolean Whether the dev server is running

Note

The default template includes JavaScript for tab switching, sidebar collapse/expand, navigation filtering, and popover positioning. If you override the scripts block, you'll need to re-implement any of these features you want to keep.

Related Pages