Skip to content
djust/docs
Appearance
Mode
djust.org →
Browse documentation

2 min read

Recipes

Patterns that come up often enough to be worth canonicalizing.

1. Brand color override (no new pack)

You don't need to author a full pack just to recolor your accent. Override the relevant tokens in your input.css:

/* static/css/input.css */
:root {
    --primary: 280 85% 60%;          /* purple */
    --primary-foreground: 0 0% 100%;
    --ring: 280 85% 60%;
    --link: 280 85% 60%;
    --link-hover: 280 85% 70%;
}

This wins over the active pack because the cascade resolves your explicit :root rule last. Switching packs still works for everything else (cards, borders, surfaces, text) — they just won't override --primary while your stylesheet is loaded.

When to use: you want one consistent brand color regardless of which shipped pack the user picked.

2. Page-level theme wrapper

A different look on a single page (e.g. a marketing landing inside an admin app):

/* static/css/input.css */
.theme-marketing {
    --background: 40 30% 7%;
    --foreground: 40 20% 92%;
    --primary: 28 85% 55%;
    --primary-foreground: 30 25% 8%;
    --card: 40 20% 9%;
    --border: 0 0% 16%;
}
{% extends "base.html" %}
{% block body %}
<body class="theme-marketing">
    {% block content %}...{% endblock %}
</body>
{% endblock %}

Tailwind utilities and djust components on that page will repaint to the overridden tokens. The user-facing pack switcher still affects every other page on the site.

When to use: a landing page with a designer-controlled palette inside an otherwise theme-switchable app.

3. Per-section accent

Sometimes one section needs a different accent without changing the rest:

/* Pricing card group with a green accent */
.pricing-grid {
    --primary: 160 60% 40%;
    --primary-foreground: 0 0% 100%;
}
<section class="pricing-grid">
    <article class="pricing-card">
        <h3>Pro</h3>
        <button class="bg-brand-rust">Choose Pro</button>
        <!--                       ^ uses --primary, now green here -->
    </article>
</section>

The CSS-variable inheritance scope means the override applies to every descendant.

4. Dark-mode-only styling without @media (prefers-color-scheme)

djust's mode switch flips a .dark class on <html> (or sets :root[data-theme="dark"], depending on pack config). Use it for any truly mode-specific styling:

.dark .my-card {
    background: hsl(var(--card));
    box-shadow: 0 4px 12px rgba(0 0 0 / 0.5);
}

:root:not(.dark) .my-card {
    background: hsl(var(--card));
    box-shadow: 0 4px 12px rgba(0 0 0 / 0.05);   /* softer in light */
}

This respects the user's session-persisted choice — prefers-color-scheme would only respect the OS-level setting and would conflict with the in-app switcher.

5. Component-scoped variable (no pack involvement)

For a component that needs a knob the pack doesn't model, declare the variable on the component root:

.toast {
    --toast-duration: 4s;
    --toast-max-width: 360px;
    animation: toast-fade var(--toast-duration);
    max-width: var(--toast-max-width);
}

To override per-instance, just inline:

<div class="toast" style="--toast-duration: 8s">Long-running message</div>

No pack changes needed.

6. Honoring system theme on first visit

Default to the OS preference for first-time visitors, persist their explicit choice afterward:

# settings.py
LIVEVIEW_CONFIG = {
    'theme': {
        'pack': 'docs',
        'default_mode': 'dark',         # used when no session + no OS hint
        'enable_dark_mode': True,
        'persist_in_session': True,
        'respect_system_preference': True,   # opt-in, falls through if no
                                             # session value is set
    },
}

The user's first visit reads prefers-color-scheme; their first explicit toggle of the mode switcher writes a session value that wins from then on.

7. Showing the active pack in a debug strip

Useful in staging — drop a small badge in the corner so the QA team can see which pack is rendering:

{% if request.user.is_staff %}
    <div class="debug-strip">
        pack: {{ request.theme.pack.name }}
        · mode: {{ request.theme.mode }}
    </div>
{% endif %}
.debug-strip {
    position: fixed; bottom: 8px; left: 8px;
    padding: 4px 8px; font-family: monospace; font-size: 11px;
    color: hsl(var(--muted-foreground));
    background: hsl(var(--card) / 0.9);
    border: 1px solid hsl(var(--border));
    border-radius: 4px;
    pointer-events: none; z-index: 9999;
}

See also

Spotted a typo or want to improve this page? Edit on GitHub →