labb 0.5.0 is out

Theming

Set up labb themes, add a custom daisyUI colour scheme, and persist a visitor’s theme choice.

labb uses daisyUI 5 for themes. Define the colours in input.css, set the active theme on the page, and save a visitor’s choice in their session if you need to.

Connect the theme controls

Start with the <c-lb.m.dependencies /> tag from Installation. Add {% labb_theme %} to the <html> element and give the dependency tag the endpoint that stores a theme choice.

templates/base.html
<html lang="en" {% labb_theme %}>
<head>
    <c-lb.m.dependencies setThemeEndpoint="{% url 'set_theme' %}" />
</head>
<body>
    {% csrf_token %}
urls.py
from django.urls import path
from labb.shortcuts import set_theme_view

urlpatterns = [
    # ... your other URLs
    path('set-theme/', set_theme_view, name='set_theme'),
]

{% labb_theme %} writes data-theme="theme-name" to <html>. It reads the user’s session and falls back to LABB_SETTINGS['DEFAULT_THEME']. Keep {% csrf_token %} in the page because the theme controller sends a POST request.

Built-in themes

labb init subscribes the project to labb’s themes CSS group. During a build, labb imports that group into .labb/labb.css. Keep the generated import in input.css.

The standard labb themes are labb-light and labb-dark. The starter CSS also enables daisyUI’s light and dark themes.

static_src/input.css
@import "tailwindcss";
@plugin "daisyui" {
  themes: light, dark;
}

/* labb CSS - don't remove this line */
@import "../.labb/labb.css";

Add a custom theme

Add an @plugin "daisyui/theme" block below the generated labb import in input.css. Do not edit .labb/labb.css; labb replaces it on every build. The daisyUI Theme Generator can help you choose values.

static_src/input.css
@plugin "daisyui/theme" {
  name: "my-brand";
  default: false;
  color-scheme: light;

  --color-primary: oklch(55% 0.3 240);
  --color-secondary: oklch(70% 0.25 200);
  --color-accent: oklch(65% 0.25 160);
  --color-base-100: oklch(98% 0.02 240);
  --color-base-content: oklch(20% 0.05 240);
  --radius-selector: 1rem;
  --radius-field: 0.25rem;
  --radius-box: 0.5rem;
}

The daisyUI theme documentation lists the available variables.

Add a theme switcher

Add the theme-controller class to a radio control, checkbox, or toggle. With the endpoint configured, labb posts the selected value to Django.

Switch to dark mode

Themed surface

Every colour here comes from the theme, so this card follows the toggle.

<div class="flex flex-col gap-4 w-full max-w-sm">
    <div class="flex items-center gap-3">
        <c-lb.toggle class="theme-controller" value="dark" size="sm" title="Toggle dark mode" />
        <span class="text-sm text-base-content/70">Switch to dark mode</span>
    </div>

    <c-lb.card border>
        <c-lb.card.body>
            <c-lb.card.title>Themed surface</c-lb.card.title>
            <p class="text-sm text-base-content/60">
                Every colour here comes from the theme, so this card follows the toggle.
            </p>
            <c-lb.card.actions>
                <c-lb.button variant="primary" size="sm">Primary</c-lb.button>
                <c-lb.button btnStyle="ghost" size="sm">Ghost</c-lb.button>
            </c-lb.card.actions>
        </c-lb.card.body>
    </c-lb.card>
</div>
<!-- Toggle dark mode -->
<c-lb.toggle class="theme-controller" value="dark" size="sm" title="Toggle dark mode" />

<!-- A checkbox works too -->
<c-lb.checkbox class="theme-controller" value="dark" title="Dark mode" />

See the Theme Controller component documentation for more examples.

Choose the default

settings.py
LABB_SETTINGS = {
    'DEFAULT_THEME': 'labb-light',  # Fallback when no theme is set
}

See settings reference for all options.

Write a custom view

Custom theme view
Use the utility functions when your app needs custom theme-selection logic instead of set_theme_view.

views.py
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from labb.shortcuts import set_labb_theme, get_labb_theme
from labb.contrib.theme import is_valid_theme_name

@require_http_methods(["POST"])
def set_theme(request):
    theme = request.POST.get("theme")
    if not theme:
        return JsonResponse({"success": False, "error": "Theme parameter is required"}, status=400)

    if not is_valid_theme_name(theme):
        return JsonResponse({"success": False, "error": "Invalid theme name"}, status=400)

    success = set_labb_theme(request, theme)
    if success:
        return JsonResponse({"success": True, "theme": theme})
    return JsonResponse({"success": False, "error": "Failed to set theme"}, status=500)

Import these functions from labb.shortcuts.

  • set_labb_theme(request, theme) stores the theme in the session and returns True or False
  • get_labb_theme(request) returns the current session value
  • set_theme_view provides the built-in persistence view

set_labb_theme stores whatever you give it. The theme name ends up in a data-theme attribute and in a CSS selector, so check it first. set_theme_view already does; a custom view should call is_valid_theme_name as above.

Fix common problems

  • The theme does not apply. Run labb build and confirm that the CSS and HTML use the same theme name.
  • The selection does not persist. Put {% csrf_token %} in <body> and set setThemeEndpoint on <c-lb.m.dependencies />.
  • Styles do not update. Refresh the browser without its cache, then restart labb dev.

Explore blocks

Useful references include daisyUI themes, the theme generator, and an OKLCH colour picker.