Spellbook provides a complete sidebar layout out of the box. You can wrap it inside your existing site, replace it entirely, or use it standalone.
Two Approaches
SPELLBOOK_BASE_EXTEND_FROM
Wraps Spellbook's sidebar layout inside your existing base template. Your site's header, footer, and navigation stay intact.
SPELLBOOK_BASE_EXTEND_FROM = 'base.html'
SPELLBOOK_MD_BASE_TEMPLATE
Replaces Spellbook's layout entirely. You control everything—sidebar, TOC, metadata, navigation.
SPELLBOOK_MD_BASE_TEMPLATE = 'my_app/custom_layout.html'
Using EXTEND_FROM
The simplest way to integrate Spellbook into an existing site.
Setup
# settings.py
SPELLBOOK_MD_PATH = BASE_DIR / 'docs'
SPELLBOOK_MD_APP = 'docs'
SPELLBOOK_BASE_EXTEND_FROM = 'base.html'
Your Base Template
Add one block where Spellbook renders:
<!-- base.html -->
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Site{% endblock %}</title>
<link rel="stylesheet" href="{% static 'css/main.css' %}">
</head>
<body>
<nav>
<!-- Your site navigation -->
</nav>
<main>
{% block spellbook %}
<!-- Spellbook sidebar + content renders here -->
{% endblock %}
</main>
<footer>
<!-- Your site footer -->
</footer>
</body>
</html>
The block must be named spellbook (not spellbook_md). Spellbook auto-generates a wrapper template that extends your base and includes the full sidebar layout.
What Gets Generated
When you run python manage.py spellbook_md, Spellbook creates:
docs/
└── templates/
└── docs/
└── spellbook_base.html ← Auto-generated wrapper
This wrapper extends your base and includes Spellbook's sidebar layout. You never edit this file—it's regenerated on each run.
Per-App Configuration
For multi-app setups:
SPELLBOOK_MD_PATH = [BASE_DIR / 'docs', BASE_DIR / 'blog']
SPELLBOOK_MD_APP = ['docs', 'blog']
SPELLBOOK_BASE_EXTEND_FROM = ['base.html', 'blog/base.html']
Using BASE_TEMPLATE
Full control over the layout. You're responsible for rendering the sidebar, TOC, metadata, and navigation.
Setup
# settings.py
SPELLBOOK_MD_PATH = BASE_DIR / 'docs'
SPELLBOOK_MD_APP = 'docs'
SPELLBOOK_MD_BASE_TEMPLATE = 'docs/spellbook_base.html'
Minimal Custom Template
At minimum, you need the content block:
<!-- docs/spellbook_base.html -->
{% extends 'base.html' %}
{% load spellbook_tags %}
{% block content %}
{% spellbook_styles %}
{% block spellbook_md %}{% endblock %}
{% endblock %}
The block must be named spellbook_md. This is where your rendered markdown content appears.
Full Custom Template
Recreate the sidebar layout with your own structure:
<!-- docs/spellbook_base.html -->
{% extends 'base.html' %}
{% load spellbook_tags %}
{% load static %}
{% block extra_css %}
{% spellbook_styles %}
<link rel="stylesheet" href="{% static 'django_spellbook/css_modules/sidebar_left.css' %}">
{% endblock %}
{% block content %}
<div class="spellbook-container">
<div class="spellbook-layout">
<nav class="spellbook-toc">
{% if is_directory_index %}
{% directory_metadata %}
{% else %}
{% page_metadata %}
{% endif %}
{% include "django_spellbook/tocs/sidebar_toc.html" %}
{% if user.is_staff %}
{% if is_directory_index %}
{% directory_metadata "for_dev" %}
{% else %}
{% page_metadata "for_dev" %}
{% endif %}
{% endif %}
</nav>
<main class="spellbook-content">
{% page_header %}
{% block spellbook_md %}{% endblock %}
</main>
</div>
</div>
{% endblock %}
The Default Layout
Spellbook's built-in sidebar_left.html provides:
{% load spellbook_tags %}
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
{% spellbook_styles %}
<link rel="stylesheet" href="{% static 'django_spellbook/css_modules/sidebar_left.css' %}">
</head>
<body class="sb-bg-background sb-text-text">
<div class="spellbook-container">
<div class="spellbook-layout">
<nav class="spellbook-toc">
{% if is_directory_index %}
{% directory_metadata %}
{% else %}
{% page_metadata %}
{% endif %}
{% include "django_spellbook/tocs/sidebar_toc.html" %}
{% if user.is_staff %}
{% if is_directory_index %}
{% directory_metadata "for_dev" %}
{% else %}
{% page_metadata "for_dev" %}
{% endif %}
{% endif %}
</nav>
<main class="spellbook-content">
{% page_header %}
{% block spellbook_md %}{% endblock %}
</main>
</div>
</div>
</body>
</html>
Template Tags Reference
spellbook_styles
Injects theme CSS variables. Required in <head>.
{% spellbook_styles %}
page_metadata / directory_metadata
Displays metadata in the sidebar. Shows different info for pages vs directories.
{# User-facing metadata (dates, tags, reading time) #}
{% page_metadata %}
{% directory_metadata %}
{# Developer metadata (URL paths, namespaces) - staff only #}
{% page_metadata "for_dev" %}
{% directory_metadata "for_dev" %}
page_header
Renders title, author, and prev/next navigation above the content.
{% page_header %}
sidebar_toc
Renders the table of contents. Usually included via template:
{% include "django_spellbook/tocs/sidebar_toc.html" %}
CSS Structure
Container Classes
| Class | Purpose |
|---|---|
.spellbook-container |
Max-width wrapper (1200px) |
.spellbook-layout |
Grid container (sidebar + content) |
.spellbook-toc |
Sidebar navigation |
.spellbook-content |
Main content area |
Grid Layout
Desktop (768px+): 3-column grid
| 250px sidebar | 800px content | flexible |
Mobile: Stacked layout with sidebar above content.
Utility Classes
The body uses theme-aware utilities:
<body class="sb-bg-background sb-text-text">
These adapt to your SPELLBOOK_THEME setting.
Context Variables
These variables are available in your templates:
| Variable | Type | Description |
|---|---|---|
toc |
dict | Table of contents tree |
metadata |
dict | Page frontmatter (title, author, dates, tags) |
current_url |
str | Current page URL name |
is_directory_index |
bool | True if this is a directory index page |
parent_directory_url |
str | URL name of parent directory |
parent_directory_name |
str | Display name of parent directory |
directory_stats |
dict | Stats for directory pages (total pages, subdirs) |
Disabling the Wrapper
For raw HTML output with no template wrapper:
SPELLBOOK_MD_BASE_TEMPLATE = None
Generated templates contain only the rendered HTML—no {% extends %}, no blocks. Useful for embedding in other systems.