# Create a Theme URL: /bengal/docs/0.5.0/theming/theme-creation/ Section: theming Tags: theming, customization, themes -------------------------------------------------------------------------------- Create a Theme Bengal's theme system supports inheritance, so you can build on the default theme and override only what you need. This guide walks through creating, customizing, and testing a theme. Scaffold a Theme # Create a site-local theme (lives in your project) bengal theme new --slug my-theme # Create an installable package (publishable to PyPI) bengal theme new --slug my-theme --mode package # Extend a specific parent theme bengal theme new --slug my-theme --extends default Site mode creates this structure: themes/my-theme/ ├── theme.toml # Name and inheritance ├── README.md ├── templates/ │ ├── base.html │ ├── home.html │ ├── page.html │ └── partials/ ├── assets/ │ └── css/ │ └── style.css # Your styles (inherits default theme's directive CSS when you extend it) Configure Your Site Point your site config at the new theme: # bengal.toml [build] theme = "my-theme" Bengal resolves templates in priority order: your theme first, then its parent (via extends), then the default theme. You only need to override the templates you want to change. Override Templates Copy a template from the active theme to customize it: # See what's available bengal theme discover # Copy a specific template bengal theme swizzle --template-path partials/header.html Swizzled templates are tracked with checksums. When the parent theme updates, bengal theme swizzle-update refreshes unchanged templates while preserving your modifications. Template Inheritance Your templates can extend parent templates: {# templates/page.html #} {% extends "page.html" %} {% block content %} <article class="my-theme-content"> {{ content | safe }} </article> {% endblock %} Bengal resolves the extends to the parent theme's page.html automatically. Add Styles Your assets/css/style.css is loaded after the parent theme's CSS, so your styles override naturally via the cascade. Directive base CSS is not bundled by the engine — it lives in the default theme at bengal/themes/default/assets/css/components/ (admonitions.css, tabs.css, dropdowns.css, steps.css, cards.css, checklist.css, code.css). So it is automatic only when your theme extends default (or is a site-local theme layered over it): in that case you inherit the functional show/hide, accessibility, and prose-contamination fixes for free and only add aesthetic styles. A theme that does not extend default must supply its own directive CSS. See What Bengal Provides vs What Your Theme Provides for the full capability-vs-presentation boundary. /* assets/css/style.css */ /* Override the primary color */ :root { --color-primary: #2563eb; --color-primary-light: #3b82f6; } /* Custom typography */ body { font-family: "Inter", system-ui, sans-serif; line-height: 1.7; } /* Style code blocks */ pre code { border-radius: 0.5rem; font-size: 0.875rem; } Test Your Theme # Start dev server with live reload bengal serve # Start theme-focused preview with active theme preflight bengal theme preview # Validate theme structure bengal theme validate --theme-path themes/my-theme # Debug template resolution bengal theme debug bengal theme debug --template page.html bengal theme preview resolves the active theme, shows whether it came from the site, Bengal's bundled themes, or an installed package, validates its metadata and required templates, then starts the live-reload server. It also prints the content, template, and theme paths the preview workflow watches. Theme Configuration Your theme.toml declares theme metadata: name = "my-theme" version = "1.0.0" description = "Documentation theme for the project" author = "Docs Team" license = "MIT" extends = "default" libraries = ["chirp_ui"] Supported metadata fields: Field Type Purpose name string Display name for bengal theme list and bengal theme info version string Theme version shown by theme tooling description string Human-readable package or project description author string Theme author or owning team license string Theme license identifier extends string Parent theme slug parent string Legacy parent theme slug, used when extends is absent libraries list of strings Python theme libraries to load, such as chirp_ui bengal theme validate --theme-path themes/my-theme checks this metadata before checking templates and assets, so malformed fields fail with direct messages. For richer configuration (feature flags, appearance, icons), use theme.yaml: name: my-theme version: "1.0.0" parent: default features: navigation: breadcrumbs: true toc: true content: code.copy: true lightbox: true search: suggest: true appearance: default_mode: system default_palette: snow-lynx Publish as a Package If you scaffolded with --mode package, your theme is a pip-installable Python package: cd bengal-theme-my-theme pip install -e . # Install locally for testing The pyproject.toml registers your theme via entry points: [project.entry-points.'bengal.themes'] my-theme = "bengal_themes.my_theme" Once installed, any Bengal site can use it: # bengal.toml [build] theme = "my-theme" Publish to PyPI with uv publish or python -m build && twine upload dist/*. Useful Commands Command Purpose bengal theme new --slug <slug> Scaffold a new theme bengal theme validate --theme-path <path> Check required files and structure bengal theme list Show available themes bengal theme info --slug <slug> Theme details and paths bengal theme discover List swizzlable templates bengal theme swizzle --template-path <template> Copy template for customization bengal theme swizzle-list List swizzled templates bengal theme swizzle-update Update unchanged swizzled templates bengal theme preview Start a theme-focused live preview server bengal theme debug Debug theme resolution chain Info Seealso Theming Overview — theme features and appearance config The Bengal Ecosystem — how Kida templates work -------------------------------------------------------------------------------- Metadata: - Author: lbliii - Word Count: 828 - Reading Time: 4 minutes