Installation

Set up Cotton UI in your Django project with Tailwind CSS and Alpine.js.

Requirements

Cotton UI needs:

  • Python 3.8+
  • Django 4.2+
  • Alpine.js v3 for interactive components (loaded from a CDN below).

Install Packages

Install via pip:

pip install django-cotton-ui

This will also install django-cotton as a dependency.

Django Settings

Add both django_cotton and django_cotton_ui to your INSTALLED_APPS:

settings.py
INSTALLED_APPS = [
    # ...
    "django_cotton",
    "django_cotton_ui",
    # ...
]

Order matters: django_cotton must come before django_cotton_ui.

Base Template Example

Link the kit's precompiled stylesheet and the Alpine bundle in your base template, then brand it by overriding the design tokens right in the <head>:

base.html
{% load static %}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Cotton UI: precompiled components + design tokens.
         Shipped inside the installed package, served by Django's staticfiles app. -->
    <link rel="stylesheet" href="{% static 'django_cotton_ui/cotton-ui.css' %}">

    <!-- Brand it: override the kit's tokens. Place this after the stylesheet link. -->
    <style>
        /* default / light mode */
        :root {
            --color-accent: var(--color-teal-500);
            --color-accent-content: var(--color-teal-600);
        }
        /* dark mode */
        .dark {
            --color-accent: var(--color-teal-400);
            --color-accent-content: var(--color-teal-300);
        }
    </style>
</head>
<body>
    {{ slot }}

    <!-- Cotton UI bundle first: it registers components on Alpine's alpine:init event -->
    <script defer src="{% static 'django_cotton_ui/cotton-ui.min.js' %}"></script>

    <!-- Alpine.js plugins, then Alpine core (deferred scripts run in order) -->
    <script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/collapse@3.x.x/dist/cdn.min.js"></script>
    <script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/focus@3.x.x/dist/cdn.min.js"></script>
    <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
</body>
</html>

Both UI kit assets serve from the installed package. With django.contrib.staticfiles enabled, {% static %} resolves them in development; run collectstatic for production. Nothing to copy or build.

Required Alpine.js Plugins

Some components need Alpine.js plugins, loaded before Alpine core:

  • @alpinejs/collapse - expand/collapse in the accordion, collapse, navbar mobile menu and navlist groups
  • @alpinejs/focus - focus trapping and keyboard navigation in dialogs, drawers, dropdowns, menus, select, popover and the calendar

Custom Build Example

Running your own Tailwind? You can't just @source the installed package (it lives in a gitignored .venv, which Tailwind skips). Instead, run the bundled command to write a file your build can scan:

python manage.py cotton_ui_sources

This writes cotton-ui.sources.css next to your project: the kit's design tokens, dark variant and the full class list as @source inline(...). @import it into your app.css and your own build generates the kit's utilities, correctly, no preflight clash, dark mode included:

app.css
@import "tailwindcss";

/* kit tokens + dark variant + class list, from `manage.py cotton_ui_sources`.
   Your build emits the kit's utilities (it resolves through .gitignore). */
@import "./cotton-ui.sources.css";

/* your own @source rules for your own templates (standard Tailwind, nothing kit-specific) */
@source "./your_app/templates/**/*.html";

/* brand it: override kit tokens with :root / .dark, NOT @theme
   (@theme loses to the kit's baked-in value; use @theme only for your own new tokens) */
:root { --color-accent: var(--color-teal-500); --color-accent-content: var(--color-teal-600); }
.dark { --color-accent: var(--color-teal-400); --color-accent-content: var(--color-teal-300); }

The class list only changes when you upgrade the kit. Rather than remember to re-run it, wire it into your build as a pre-step, the command is fast and deterministic, so running it every build keeps the list in sync automatically:

package.json
{
  "scripts": {
    "prebuild": "python manage.py cotton_ui_sources",
    "build": "tailwindcss -i app.css -o static/app.css --minify"
  }
}

No node build? Chain it the same way in a Makefile or CI step: python manage.py cotton_ui_sources && ...build.... With django-tailwind-cli or django-tailwind, run cotton_ui_sources just before their build command. You don't <link> the kit's CSS on this path, your build already contains everything.

Theming & verifying

A neutral zinc accent ships by default. Brand it by overriding the accent tokens, in the inline <style> from the base template above (no build) or your app.css after the kit @import (custom build), with a .dark block for dark mode. The Theming guide covers the full token set, accent presets and gray palettes.

Verify it works

Drop a couple of components into a template. They should render styled, with the primary button in your accent colour:

<c-ui.button variant="primary">Primary Button</c-ui.button>
<c-ui.button variant="default">Default Button</c-ui.button>
{% cotton ui.button variant="primary" %}Primary Button{% endcotton %}
{% cotton ui.button variant="default" %}Default Button{% endcotton %}