Building a Custom Theme¶
A theme in SmallBlock CMS controls your site’s appearance — its typography, colors, spacing, and the overall structure of each page. In this tutorial, you’ll create a custom theme from scratch, define a reusable color system, and override templates to give your site a distinct look and identity.
This tutorial builds on concepts from earlier lessons and is ideal if you want to personalize a project or develop themes for reuse across multiple sites.
—
Before You Begin¶
You should have:
Completed the Build Your First Site tutorial.
A basic understanding of HTML and CSS.
A running development server.
Access to your project’s file structure.
—
How Themes Work in SmallBlock¶
A theme contains:
Templates — HTML structure.
Static assets — CSS, JavaScript, images.
Metadata — theme name, version, color variables.
SmallBlock loads the selected theme at startup, injecting theme-defined colors and assets automatically into the template environment.
The theme resolution flow looks like this:
![digraph G {
rankdir=LR;
node [shape=box, style="rounded,filled", fillcolor="#eef3f8"];
A [label="settings.ini\n(site.theme = prussian_dark)"];
B [label="Theme Loader"];
C [label="Load Templates\n& Static Assets"];
D [label="Render Page with Theme"];
A -> B -> C -> D;
}](../_images/graphviz-9a94c4c9f5e1c3ffb883ad75598fc75d148c9c1c.png)
—
Step 1 — Create the Theme Directory¶
Themes live under the themes/ directory in your project root.
cd mysite
mkdir -p themes/prussian_dark
cd themes/prussian_dark
A typical theme may look like this:
prussian_dark/
├── templates/
├── static/
│ ├── css/
│ └── images/
└── theme.ini
Create the folders:
mkdir -p templates
mkdir -p static/css
mkdir -p static/images
—
Step 2 — Define Theme Metadata¶
Create theme.ini:
[theme]
name = Prussian Dark
description = A dark, minimal theme with Prussian blue highlights.
author = Your Name
version = 1.0
[colors]
background = #0f1c2c
surface = #13273d
accent = #23445a
text_primary = #e6edf3
text_muted = #9baec8
These values become available in templates and can be referenced in CSS using the theme loader or by manually defining CSS variables.
—
Step 3 — Create the Base Template¶
Inside templates/, create base.html:
<!DOCTYPE html>
<html lang="{{ language or 'en' }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ page.title }} — {{ site_name }}</title>
<link rel="stylesheet" href="{{ static('css/style.css') }}">
</head>
<body>
<header class="site-header">
<h1><a href="/">{{ site_name }}</a></h1>
<nav class="main-nav">
{% for item in nav %}
<a href="{{ item.url }}">{{ item.title }}</a>
{% endfor %}
</nav>
</header>
<main class="content">
{{ content }}
</main>
<footer class="site-footer">
<p>© {{ current_year }} {{ site_name }}</p>
</footer>
</body>
</html>
This is the foundation for all pages in your theme.
—
Step 4 — Add Styles¶
Create static/css/style.css:
:root {
--bg: #0f1c2c;
--surface: #13273d;
--accent: #23445a;
--text: #e6edf3;
--muted: #9baec8;
}
body {
background-color: var(--bg);
color: var(--text);
font-family: system-ui, sans-serif;
margin: 0;
line-height: 1.6;
}
a {
color: var(--muted);
text-decoration: none;
}
a:hover {
color: var(--text);
}
.site-header,
.site-footer {
background-color: var(--surface);
padding: 1em;
border-bottom: 2px solid var(--accent);
}
.main-nav a {
margin-right: 1em;
}
.content {
padding: 2rem;
}
At this point, your theme should already start to resemble a cohesive dark UI.
—
Step 5 — Register and Activate the Theme¶
Open config/settings.ini and set:
[site]
theme = prussian_dark
Restart the development server:
smallblock runserver
Visit your site — the new Prussian Dark theme should now be active.
—
Step 6 — Override CMS Templates¶
To customize specific page types or components, you can override templates from SmallBlock’s internal defaults.
For example, to override the default page view:
touch templates/page.html
Add custom markup:
{% extends "base.html" %}
{% block content %}
<article class="page">
<h2>{{ page.title }}</h2>
<div class="page-body">
{{ page.body_html|safe }}
</div>
</article>
{% endblock %}
Or override navigation, sidebars, blocks, or any template your project uses.
—
Step 7 — Add Custom Assets (Optional)¶
You can include images, icons, or theme-specific JavaScript:
<script src="{{ static('js/theme.js') }}"></script>
SmallBlock automatically resolves static paths based on the active theme.
—
Step 8 — Verify the Theme¶
Check that:
The base template loads successfully
CSS is applied and colors match your theme.ini palette
Navigation links resolve correctly
Overridden templates render as expected
Language context (if multilingual) still works with your layout
Use browser dev tools to confirm your assets load from:
/themes/prussian_dark/static/...
—
Troubleshooting¶
Theme not applying?
Ensure
theme = prussian_darkis set under[site].Restart the server — themes load at startup.
Check directory name and spelling.
Styles missing?
Confirm CSS is placed in
static/css/style.css.Verify template includes the CSS link:
<link rel="stylesheet" href="{{ static('css/style.css') }}">
Overridden template not used?
Ensure filenames match the CMS’s internal template names.
Clear any template caching (restart server).
—
Next Steps¶
Continue exploring advanced customization:
Extend the Toolbar — integrate theme styling with editor UI elements.
Using Template Tags — create data-driven components for your theme.
Concepts: Templates — understand how templates flow through the system.