Customize Themes

Customize existing themes without breaking updates

3 min read 630 words

Customize Bengal themes without breaking theme updates. Use theme inheritance, template overrides, and CSS customization techniques.

Understand Theme Resolution

Bengal resolves themes in this order:

  1. Project themes -themes/your-theme/(highest priority)
  2. Installed themes - Installed via pip/uv
  3. Bundled themes - Built into Bengal (e.g.,default)

Check Active Theme

1
2
3
4
5
6
7
8
# List available themes
bengal utils theme list

# Get theme info
bengal utils theme info default

# Debug theme resolution
bengal utils theme debug

Create a Project Theme

Option 1: Start from Scratch

bengal new theme my-custom-theme

This creates:

themes/my-custom-theme/
├── theme.yaml
├── templates/
│   ├── base.html
│   ├── page.html
│   └── partials/
│       ├── header.html
│       └── footer.html
└── static/
    ├── css/
    │   └── style.css
    └── js/
        └── main.js

Configure Your Theme

Editbengal.toml:

1
2
3
[theme]
name = "my-custom-theme"
default_appearance = "light"

Override Templates Selectively

Template Inheritance

You don't need to copy all templates. Override only what you need:

themes/my-custom-theme/templates/base.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{# Extend default theme's base template #}
{% extends "default::base.html" %}

{# Override only the header block #}
{% block header %}
<header class="custom-header">
    <h1>{{ site.title }}</h1>
    <nav>
        {% for item in menu.main %}
        <a href="{{ item.url }}">{{ item.name }}</a>
        {% endfor %}
    </nav>
</header>
{% endblock %}

{# Everything else inherits from default theme #}

Partial Overrides

Override specific partials:

themes/my-custom-theme/templates/partials/footer.html:

1
2
3
4
<footer class="custom-footer">
    <p>&copy; {{ site.author }} {{ "now" | date("%Y") }}</p>
    <p>Custom footer content</p>
</footer>

Bengal will use your partial instead of the theme's default.

Customize CSS

Method 1: Override Theme CSS

Create your own CSS file that overrides theme styles:

themes/my-custom-theme/static/css/custom.css:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
/* Override theme colors */
:root {
    --color-primary: #3498db;
    --color-text: #2c3e50;
}

/* Custom styles */
.custom-header {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    padding: 2rem;
}

Include in your base template:

themes/my-custom-theme/templates/base.html:

1
2
3
4
5
{% extends "default::base.html" %}

{% block extra_head %}
<link rel="stylesheet" href="{{ asset_url('css/custom.css') }}">
{% endblock %}

Method 2: Use CSS Variables

Many themes support CSS variables. Override them:

themes/my-custom-theme/static/css/overrides.css:

1
2
3
4
5
6
:root {
    /* Override default theme variables */
    --theme-primary: #3498db;
    --theme-secondary: #2ecc71;
    --theme-font-sans: 'Inter', sans-serif;
}

Theme Configuration Options

Themes can expose configuration options:

themes/my-custom-theme/theme.yaml:

1
2
3
4
5
6
7
8
9
name: my-custom-theme
version: 1.0.0
description: Customizable theme

params:
  show_author: true
  show_date: true
  sidebar_position: left
  color_scheme: light

Access in templates:

1
2
3
{% if theme.config.params.show_author %}
<p>By {{ page.author or site.author }}</p>
{% endif %}

Configure inbengal.toml:

1
2
3
4
5
6
7
[theme]
name = "my-custom-theme"

[theme.params]
show_author = true
sidebar_position = "right"
color_scheme = "dark"

Best Practices

Don't Modify Installed Themes

Bad:

1
2
# Don't edit installed theme directly
vim $(python -m site --user-site)/bengal/themes/default/templates/base.html

Good:

1
2
3
# Create project theme that extends default
bengal new theme my-theme
# Override only what you need

Use Theme Inheritance

Good:

1
2
3
4
{% extends "default::base.html" %}
{% block header %}
  {# Only override header #}
{% endblock %}

Bad:

1
2
3
4
5
{# Copying entire base.html #}
<!DOCTYPE html>
<html>
  {# ... hundreds of lines ... #}
</html>

Troubleshooting

Seealso