---
title: "Troubleshooting"
slug: theming-troubleshooting
section: theming
order: 90
level: intermediate
description: "Color leaks, 'why is my page unstyled when I switch packs', stale Tailwind output, and the rest of the theming bug catalog."
---

# Troubleshooting

A guided tour of the failure modes we've seen, in rough order of
frequency.

## "My layout collapses when I switch packs."

Almost always one of:

### 1. You wrote structural CSS into the theme pack

The new pack doesn't have those rules; the page falls back to default
styling. See [Structure vs. style](/theming/structure-vs-style/) — the
fix is to move structural CSS into your project's `static/css/input.css`.

### 2. You hard-coded a hex color in CSS

Hex doesn't move when the pack changes. Grep your stylesheets:

```bash
grep -nE '#[0-9a-fA-F]{3,8}' static/css/input.css
```

Replace with `hsl(var(--…))` references to the appropriate token. See
[Tokens](/theming/tokens/) for the vocabulary.

### 3. Your Tailwind output is stale

If you're using Tailwind, rebuild after editing `input.css`:

```bash
make tailwind-build
```

In dev with `make tailwind-watch` running, this happens automatically —
but a stopped watcher leaves you with a stale `output.css`.

## "The new pack's colors don't show up at all."

### 1. Your stylesheet's `:root` overrides win

If your `static/css/input.css` declares `:root { --primary: …; }`, that
takes precedence over the pack's emitted variable because cascade order
favors the later rule. Either remove the override (use the pack's
value) or scope it (`.theme-marketing { --primary: …; }`) per
[Recipes](/theming/recipes/).

### 2. Pack registration didn't run

Confirm the pack is registered:

```python
from djust.theming import get_registry
print('sunset' in [p.name for p in get_registry().list_packs()])
```

If `False`, your `apps.py:ready()` hook isn't running. Check
`INSTALLED_APPS`, restart the dev server.

### 3. Pack name typo in settings

`LIVEVIEW_CONFIG['theme']['pack']` is case-sensitive. djust falls back
to the default pack with a warning if the name doesn't match a
registered pack. Check the dev console for:

```text
W001  Theme pack 'sunsey' not registered; falling back to 'shadcn'.
```

## "Pack switch doesn't persist."

### 1. `persist_in_session` is `False`

Check `LIVEVIEW_CONFIG['theme']['persist_in_session']`. Default is
`True`; if you've turned it off, the choice only applies for the
current page render.

### 2. Sessions aren't enabled

`django.contrib.sessions` must be in `INSTALLED_APPS` and the session
middleware must be in `MIDDLEWARE`. djust depends on Django's session
machinery to persist the choice.

### 3. Two djust projects on the same shared domain

Browsers scope cookies by domain (not port). If you run docs.djust.org
on `:8003` and your demo on `:8001`, they fight over the same cookie.
Set `cookie_namespace` on each — see
[Runtime switching](/theming/runtime-switching/).

## "Mode toggle doesn't appear in the theme panel."

`LIVEVIEW_CONFIG['theme']['enable_dark_mode'] = False` hides the mode
toggle. Set to `True` to expose it.

The pack must also define both `light` and `dark` token sets — packs
that only define one mode hide the toggle automatically.

## "FOUC — wrong theme flashes on page load."

The active pack is rendered server-side, so the *initial* paint is
correct. FOUC comes from one of:

### 1. Your base template doesn't include the anti-FOUC inline `<script>`

djust's shipped base templates include a small `<head>` script that
syncs localStorage to the cookie before first paint. If you wrote your
own base template, copy the pattern from
[`djust/templates/djust_theming/_anti_fouc.html`](https://github.com/djust-org/djust/blob/main/python/djust/theming/templates/djust_theming/_anti_fouc.html).

### 2. The CSS variable block is loaded *after* the body content

The `<style>` block djust emits with the active tokens needs to be in
`<head>`, before any user-visible content. Confirm your base template
puts `{% theme_css %}` (or the equivalent context-processor render) in
`<head>`.

## "Components look wrong but the colors are right."

Components inherit the theme's design system (typography, layout,
animation, interaction) in addition to colors. If the *shape* looks
wrong (button radius, focus ring style, density), check that the
`DesignSystem` in the active pack matches what you expect.

To see the active design system:

```python
from djust.theming import get_active_pack
pack = get_active_pack(request)
print(pack.design_theme)              # 'shadcn', 'editorial', 'material', …
```

If a pack mixes a custom preset with a shipped design system, swapping
the design system independently is one fix; authoring a pack with the
right design system is another.

## "I want to know exactly which CSS variables are emitted right now."

The dev panel at `/_djust/panel/` (when `DEBUG=True`) has a Theming
tab that shows the full token table for the active pack and mode. Copy
any value from there to use in custom CSS.

For programmatic access:

```python
from djust.theming import generate_pack_css
print(generate_pack_css('docs'))
```

Returns the complete CSS for that pack. Mode is not a parameter: light and
dark are both in the one stylesheet, selected by CSS (`.dark`), so there is
no per-mode string to ask for.

## "Switching packs is slow."

Pack swap is a session write + a per-request CSS regeneration. The CSS
regeneration is in-memory and sub-millisecond — the latency is
dominated by your session backend (Redis < cookie < DB). If you see
real latency, profile your session writes.

## See also

- **[Settings](/theming/settings/)** — verify `pack`, `default_mode`,
  `persist_in_session`, `enable_dark_mode` against this checklist.
- **[Structure vs. style](/theming/structure-vs-style/)** — the most
  common failure mode, in detail.
- **[Tokens](/theming/tokens/)** — the canonical variable reference.
