Skip to content
Documentation

Getting Started

Production-ready theming and 177+ components for Django. 12 design systems × 20 color presets = 240 unique theme combinations. No build step. No JavaScript framework.

What's Included

177+
Components
across 9 categories
240
Theme Combinations
12 systems × 20 presets
2
Packages
djust-theming + djust-components
0
Build Steps
pure CSS, no Node, no bundler

Step 1 — Install

terminal
$ pip install djust-theming djust-components

# or with uv:
$ uv add djust-theming djust-components

Requires Python 3.10+ and Django 4.0+. No Node.js, no npm, no bundler.

Step 2 — Configure

Add both packages to INSTALLED_APPS, include the URLs, and register the context processor:

settings.py
INSTALLED_APPS = [
    'djust_theming',
    'djust_components',
    ...existing apps...
]

TEMPLATES = [{
    ...existing config...
    'OPTIONS': {
        'context_processors': [
            ...existing processors...
            'djust_theming.context_processors.theme_context',
        ],
    },
}]

LIVEVIEW_CONFIG = {
    'theme': {
        'preset': 'blue',
        'default_mode': 'system',
    }
}
urls.py
from django.urls import path, include

urlpatterns = [
    ...your urls...
    path(
        'theming/',
        include('djust_theming.urls'),
    ),
]

The URL include enables the /theming/gallery/, /theming/gallery/storybook/, and /theming/gallery/editor/ developer tools.

Step 3 — Add to Templates

Use {% theme_head %} in every page that needs theming. It inlines critical CSS tokens and defers the rest — no flash of unstyled content.

base.html
{% load theme_tags djust_components %}
<!DOCTYPE html>
<html>
<head>
    {% theme_head %}  <!-- inlines tokens, defers components.css -->
</head>
<body>
    {% theme_switcher %}  <!-- optional: light/dark + preset selector -->

    <!-- djust-theming template tags -->
    {% theme_button "Save" variant="primary" %}

    <!-- djust-components template tags -->
    {% alert variant="success" %}Done!{% endalert %}
    {% badge label="New" status="success" %}
    {% dj_button label="Submit" variant="primary" %}

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

djust-theming tags

{% load theme_tags %}

  • theme_head — CSS tokens + anti-FOUC script
  • theme_switcher — Mode + preset selector UI
  • theme_mode_toggle — Light/dark/system toggle
  • theme_preset_selector — Preset picker (dropdown or grid)
  • theme_form — Instantly style any Django form
  • theme_button, theme_card, theme_alert, ...

djust-components tags

{% load djust_components %}

  • alert, badge, card, callout — Display
  • dj_button, dj_input, dj_select — Form controls
  • modal, tabs, accordion, dropdown — Interactive
  • data_table, data_grid, stat_card — Data display
  • bar_chart, line_chart, sparkline — Charts
  • ...and 177 total

Automatic System Checks

djust-theming registers Django system checks that run at startup. Misconfigured presets, missing context processors, and WCAG contrast failures are caught before your first request.

Check ID Issue
E001 Context processor not in TEMPLATES
E002 Preset name doesn't exist
E003 Design system name doesn't exist
W001 Color pair fails WCAG AA contrast (4.5:1)
terminal
$ python manage.py check

System check identified no issues.

# Silence a check after review:
SILENCED_SYSTEM_CHECKS = [
    'djust_theming.W001'
]

JavaScript API

Available globally as window.djustTheme when {% theme_head %} is loaded.

browser console
// Change mode
djustTheme.setMode('dark');    // light | dark | system
djustTheme.toggle();            // toggle light ↔ dark

// Change color preset
djustTheme.setPreset('blue');  // any preset name

// Query current state
djustTheme.getMode();          // 'light' | 'dark' | 'system'
djustTheme.getResolvedMode();  // always 'light' or 'dark'

// Listen for changes
window.addEventListener('djust-theme-changed', (e) => {
    console.log(e.detail.mode, e.detail.resolvedMode);
});

Session persistence

Theme state is persisted in both localStorage (client-side) and session (server-side). The server uses session values for SSR, so the first render is always correct even without JavaScript.

Anti-FOUC protection

Critical CSS tokens are inlined in <style>, component CSS is deferred via preload. A small inline script applies the correct theme class before first paint — no flash of light mode on a dark-mode session.

Developer Tools

Available in DEBUG=True or for is_staff users. Include the URLs to enable them.

Management Commands

terminal
# Scaffold a new theme
python manage.py djust_theme create-theme my-brand --preset blue --design-system minimalist

# List all presets
python manage.py djust_theme list-presets

# Export preset colors for Tailwind
python manage.py djust_theme tailwind-config --preset blue --output tailwind.config.js

# Import/export shadcn/ui themes
python manage.py djust_theme shadcn-import my-theme.json
python manage.py djust_theme shadcn-export --preset blue --output blue-theme.json

# Validate a custom theme before publishing
python manage.py djust_theme validate-theme my-brand
python manage.py djust_theme check-compat my-brand
Components →

177+ components across 9 categories with live demos.

Themes →

240 combinations — 12 systems × 20 presets.

Customize →

4 levels from one-line preset swap to publishable theme packages.

Integration →

How theming and components work together under the hood.