Skip to main content

Wagtail DaisyUI Interface Editor

CI — lint & tests

Create reusable DaisyUI themes through Wagtail, apply them to pages, and build navigation menus from the same block components.

Supported versions

This package supports Wagtail 7.3 and up, and all compatible versions of Python and Django.

Installation

uv add wagtail-daisIE
poetry add wagtail-daisIE
pip install wagtail-daisIE

1. Add to INSTALLED_APPS

# myproject/settings.py
INSTALLED_APPS = [
    "wagtail_daisIE",
    # ...
    "wagtail",
    # ...
    "wagtail.contrib.table_block",
    # ...
    "colorfield",
]

2. Run migrations

python manage.py migrate

3. Build the global stylesheet

The package ships a compiled Tailwind v4 + DaisyUI stylesheet. If you change source.css, rebuild it:

npm run compile-global-css

Quick start

Create a theme

In the Wagtail admin, open Design → Themes and create a theme. Configure:

  • Name — a unique identifier (used as the data-theme value).
  • Set as default / Set as default dark theme — fallbacks.
  • Color scheme — light, dark, or normal.
  • Colors — primary, secondary, accent, neutral, base surfaces, semantic colors.
  • Border radii, Sizes, Effects — DaisyUI design tokens.
  • Background — solid, gradient, or image layers.
  • Fonts — font families by role (heading, body, subheading, code, or custom) with fallbacks, base font size and line height.
  • Font CDNs — stylesheet links for webfonts (e.g. Google Fonts).

Use the page mixin

StyledPageMixin adds a theme, per-page background layers, and a content body StreamField to any Wagtail page:

from wagtail_daisIE.pages import StyledPageMixin


class MyPage(StyledPageMixin):
    content_panels = (
        StyledPageMixin.content_panels
        + [
            # Add any custom panels here
        ]
    )

This mixin adds:

  • page_theme — a ForeignKey(DaisyUITheme) (defaults to the default theme).
  • page_background — background layers that override the theme for this page.
  • body — a StreamField of content blocks.
  • get_daisyui_theme() — returns page_theme or the default theme.
  • Context variables daisyui_theme and daisyui_page_background_css.

Render the theme in your templates

{% load wagtailcore_tags wagtail_daisIE_tags %}
<!DOCTYPE html>
<html{% if daisyui_theme %} data-theme="{{ daisyui_theme.name }}"{% endif %}>
    <head>
        <link rel="stylesheet" href="{% daisyui_global_css %}" />
        {% daisyui_theme_full_css daisyui_theme %}
        {% daisyui_icon_assets %}
    </head>
    <body{% if daisyui_page_background_css %} style="background: {{ daisyui_page_background_css }}"{% endif %}>
        {% block content %}{% endblock %}
    </body>
</html>

{% daisyui_global_css %} returns the URL of the bundled Tailwind/DaisyUI stylesheet; remove conflicting stylesheets (Bootstrap, other Tailwind builds).

{% daisyui_theme_full_css theme %} emits the theme's color, radius, size, effect, background, font, and font-CDN CSS. Finer-grained tags are listed below.

Menus

DaisyUIMenu is a reusable snippet rendered with the {% daisyui_menu %} tag. Menus reuse the same blocks as page bodies, so content components behave identically in both contexts.

{% load wagtail_daisIE_tags %}
{% daisyui_menu "Main navigation" %}
{% daisyui_menu "Footer" css_class="bg-base-200" %}

Each menu has:

  • Layout — navbar, footer, sidebar, horizontal, or vertical.
  • Branding — a logo and/or wordmark, optionally wrapped in one destination link (page, URL, document, email, or phone).
  • Search — an optional search box with configurable URL, parameter, and placeholder.
  • Theme — a menu_theme (falls back to the default theme) plus an optional light/dark toggle.
  • Item defaults (item_design) — default typography, background, spacing, size, border and box styles applied to every item. Each item's own settings are appended on top, so per-block design still wins.
  • Menu items — links, buttons, search boxes, inline cards, accordions, link lists, headers, text, and newsletters.

Blocks and design

Design primitives live in wagtail_daisIE.base_blocks and are composed into the public blocks in wagtail_daisIE.blocks. Every themed block resolves a block_css class string from its design settings, merging any inherited block_css from its parent context. This is what lets menu-level item_design defaults cascade into items without any menu-specific block code.

Any block with a typography group (a TypographyBlock) exposes a Font family picker populated from the current theme's font-family roles. The stored value is the role (or custom name) and renders as font-<role>.

Audience restrictions

Content blocks expose an audience field so editors can restrict content. Audiences are declared in settings and evaluated at render time.

# mysite/settings/base.py
WAGTAIL_DAISIE_AUDIENCE_RULES = {
    "adults": {"label": "Adults", "rule": "home.audience.is_adult"},
    "verified": {"label": "Verified users", "rule": "home.audience.is_verified"},
}
# mysite/home/audience.py
def is_adult(request):
    user = getattr(request, "user", None)
    return bool(user and user.is_authenticated and getattr(user, "age", 0) >= 18)

Each rule is a dotted path to a callable invoked as rule(request) returning a boolean. Selecting multiple audiences is a logical OR. If WAGTAIL_DAISIE_AUDIENCE_RULES is empty, the audience field is hidden.

For campaigns (which have no request) a rule may also declare a queryset returning a User queryset — see docs/notifications.md.

Context models and dynamic content

Expose project models so authors can reference them from any block:

WAGTAIL_DAISIE_CONTEXT_MODELS = {
    "user": {"label": "Current user", "model": "users.User", "source": "request.user"},
    "meeting": {
        "label": "Meeting",
        "model": "meetings.Meeting",
        "source": "url",
        "lookup_field": "slug",
        "url_source": "get_absolute_url",
    },
}

Then use {{ user.first_name }}, {{ meeting.url }} in text, rich text, Image blocks (dynamic source) and link destinations. Pages can pin a value to a specific instance or resolve it from the URL. Full guide: docs/context-models.md.

Data components

Render project data and trigger actions with reusable components:

  • Feeds — a snippet (Design → Feeds) that lists a context model with admin-designed item cards, typed filters (choice/multi, boolean, date, date range, price range, search), AJAX filtering and optional infinite scroll.
  • Action button — posts to a developer-defined action (WAGTAIL_DAISIE_ACTIONS), e.g. Add to basket.
  • Calendar — a Cally date picker showing each day's events as designed cards.
WAGTAIL_DAISIE_ACTIONS = {
    "basket.add": {
        "label": "Add to basket",
        "handler": "myapp.actions.add_to_basket",
    },
}
# urls.py
(path("daisie/", include("wagtail_daisIE.dynamic.urls")),)

Full guide: docs/data-components.md.

Emails and notifications

Build responsive MJML emails from the same design primitives and edit them in Wagtail, with {{ payload.* }} placeholders and an admin help panel listing what's available:

WAGTAIL_DAISIE_NOTIFICATION_BRIDGES = {
    "booking_requested": {
        "label": "Booking requested",
        "template": "Booking requested",
        "signal": "myapp.signals.booking_requested",
        "sender": "myapp.models.MeetingRequest",
    },
}

Form pages

DaisieFormPage renders DaisyUI forms, links each input to a model field, styles inputs and labels individually, and can create a configured model instance from a submission (with an optional approval flag, success/error bodies and a success redirect). See docs/forms.md.

Error pages

ErrorPage snippets provide themed bodies for supported HTTP statuses. Wire Django's handlers in the root URL configuration; audience-gated pages can also render the 403 snippet directly. See docs/error-pages.md.

Icons

Icons are stored as "<prefix>:<name>" (e.g. mdi:home) or as raw CSS classes (e.g. fa-solid fa-home). Four providers ship with the package:

Provider Prefix example Notes
wagtail wagtail:home Built-in Wagtail admin icons, rendered inline.
iconify mdi:home On-demand icons from Iconify (cached server-side).
font fa6-solid:house Any webfont rendered via CSS classes.
custom brand:mark A project-supplied IconifyJSON or name-to-SVG manifest.

Icon sources are managed under Design → Icon Sources. Render an icon with {% daisyui_icon value %} and include provider assets with {% daisyui_icon_assets %} (or the icon_assets context processor).

from wagtail import hooks


@hooks.register("register_icon_providers")
def register_icon_providers(providers):
    return providers + [MyIconProvider()]

Template tags

Tag Type Output
{% daisyui_global_css %} Simple URL of the bundled Tailwind/DaisyUI stylesheet
{% daisyui_theme_css theme %} Inclusion Inline <style> with color/radius/size/effect variables
{% daisyui_theme_inline_css theme %} Simple Raw theme CSS string
{% daisyui_theme_background_css theme %} Inclusion Inline <style> for background layers
{% daisyui_theme_background_inline_css theme %} Simple Raw background CSS string
{% daisyui_theme_font_css theme %} Inclusion Inline <style> with --font-* variables
{% daisyui_theme_font_cdns theme %} Inclusion <link> tags for font CDNs
{% daisyui_theme_full_css theme %} Inclusion Font CDNs + colors + background + fonts
{% daisyui_theme_full_inline_css theme %} Simple Raw combined CSS string
{% daisyui_menu "Name" %} Inclusion Renders a DaisyUIMenu snippet
{% daisyui_icon value %} Simple Renders a stored icon value
{% daisyui_icon_assets %} Inclusion Provider scripts/styles for <head>
{{ item|is_active:request }} Filter Whether a menu item points at the current path

Settings

No Django settings are required. The following are optional:

# settings.py
WAGTAIL_DAISIE_ICONS = {
    "iconify": {
        "api": "https://api.iconify.design",  # or a self-hosted API
        "mode": "cached-svg",  # or "component"
        "collections": ["mdi", "fa6-solid", "lucide"],
        "timeout": 3,
    },
    "cache_timeout": 604800,
}

WAGTAIL_DAISIE_AUDIENCE_RULES = {
    "adults": {"label": "Adults", "rule": "home.audience.is_adult"},
}

WAGTAIL_DAISIE_CONTEXT_MODELS = {
    "user": {"label": "Current user", "model": "users.User", "source": "request.user"},
}

WAGTAIL_DAISIE_NOTIFICATION_BRIDGES = {
    "booking_requested": {
        "label": "Booking requested",
        "template": "Booking requested",
        "signal": "myapp.signals.booking_requested",
        "sender": "myapp.models.MeetingRequest",
    },
}

# Requires the [allauth] extra.
WAGTAIL_DAISIE_ALLAUTH_UI = True

WAGTAIL_DAISIE_ACTIONS = {
    "basket.add": {"label": "Add to basket", "handler": "myapp.actions.add"},
}

# Optional: self-hosted Cally for the calendar block.
WAGTAIL_DAISIE_CALLY_URL = "https://unpkg.com/cally"

Demo

The demo/ project is a DaisyUI-styled Wagtail site. Run it with just demo (migrate, load data, collect static, runserver) or load only the data with just load_initial_data.

The loader reads demo/fixtures/content.json and demo/fixtures/media/original_images/, then seeds related snippets programmatically, including themes, menus, 403/404/500 error pages, email templates, notification audiences and feeds. It is idempotent (use --force to recreate content). See demo/fixtures/README.md for the fixture schema.

The demo wires the 403, 404 and 500 handlers. Since just demo enables DEBUG=True, check the designed 404 and 500 responses with non-debug settings; the audience-gated 403 renders directly in either mode.

The demo also showcases the notification, context-model, form and allauth features:

  • Context and components page — context models plus feedback/data-input blocks.
  • Members only page — audience-gated with a designed 403 error page.
  • Suggest a bread — a DaisieFormPage that creates an unapproved BreadSuggestion for review.
  • Newsletter in the footer — posts to the Daisie subscribe endpoint and populates the Newsletter audience.
  • Breads and basket — a Model list of the Bread model with an Add to basket action button, a session basket list, and a Clear basket action (a cart parallel).
  • Bread calendar — the breads grouped by added_on in a Cally calendar.
  • Blog feed — the blog index renders a filterable feed (tag/author/date) of live posts with AJAX pagination.
  • Blog post published — a notification bridge emailing that audience.
  • Account pages at /accounts/ — DaisyUI allauth pages and emails, with sample Account confirmation and Password reset email templates.
  • Admin user admin / changeme.

Development

See CONTRIBUTING.md and docs/.

just install     # Install Python and Node.js dependencies
just demo        # Run the demo site
just test        # Run tests
just lint        # Run all linters

License

wagtail-daisIE is licensed under the BSD 3-Clause License.

Release files for wagtail-daisIE 1.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wagtail-daisIE 1.2.0
File Size Uploaded
wagtail_daisie-1.2.0.tar.gz 249.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for wagtail-daisIE 1.2.0
File Interpreter ABI Platform
wagtail_daisie-1.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 600.4 kB

Release files / wagtail_daisie-1.2.0.tar.gz

Download URL wagtail_daisie-1.2.0.tar.gz
Size 249.3 kB
Tags Source
SHA-256 checksum
How to use checksums
b7de4989572c3b9aabe99512a51af1c11caf890d930d549c4b6a0e7676725594
BLAKE2b-256 checksum
How to use checksums
100fd77e87e1584bae86287343a47b12b700db76c2ba60d8a3870f2f3f0b1c1e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release files / wagtail_daisie-1.2.0-py3-none-any.whl

Download URL wagtail_daisie-1.2.0-py3-none-any.whl
Size 351.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b34d32ad303026903745fa632f8481390e835d4d2dc18088669dbf34aafd087e
BLAKE2b-256 checksum
How to use checksums
431428de112f7db7bdd4372621a2be75e637d62f76807f814b4299ea452cad17
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.2.0 This release

2 release files

1.1.0

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page