Build reusable components for Django. No Python required.

Compose UI from single template files. No build step, fully interoperable with the Django templates you already write.

1. Define a component

card.html
<div class="card">
    <h3>{{ title }}</h3>
    <p>{{ slot }}</p>
</div>

2. Use it like a tag

view.html
<c-card title="Pricing">
    Simple, per-seat billing.
</c-card>

<c-card title="Support">
    Help when you need it.
</c-card>
{% cotton card title="Pricing" %}
    Simple, per-seat billing.
{% endcotton %}

{% cotton card title="Support" %}
    Help when you need it.
{% endcotton %}

3. Renders to

Pricing

Simple, per-seat billing.

Support

Help when you need it.

1. Define a component

field.html
<c-vars label type="text" :required="False" />

<div class="field">
    <label>{{ label }}{% if required %} *{% endif %}</label>
    <input type="{{ type }}" {{ attrs }} />
</div>
{% cotton:vars label type="text" :required="False" %}

<div class="field">
    <label>{{ label }}{% if required %} *{% endif %}</label>
    <input type="{{ type }}" {{ attrs }} />
</div>

2. Props change the output

view.html
<c-field label="Email" type="email" required />

<c-field label="Age" type="number"
    placeholder="18+" />
{% cotton field label="Email" type="email" required /%}

{% cotton field
    label="Age"
    type="number"
    placeholder="18+"
/%}

3. Renders to

1. Define a component

button.html
<c-vars variant="primary" />

<button class="btn btn-{{ variant }}">
    {{ slot }}
</button>
{% cotton:vars variant="primary" %}

<button class="btn btn-{{ variant }}">
    {{ slot }}
</button>

2. One prop, many looks

view.html
<c-button>Save</c-button>
<c-button variant="default">Cancel</c-button>
<c-button variant="danger">Delete</c-button>
{% cotton button %}Save{% endcotton %}
{% cotton button variant="default" %}Cancel{% endcotton %}
{% cotton button variant="danger" %}Delete{% endcotton %}

3. Renders to

New to components? Start with Thinking in Components.

Why cotton?

Rapid UI composition
Create reusable UI components from a single HTML file, no Python required. Composing from small, modular pieces streamlines your workflow and boosts productivity.
Style it your way
Components own their markup, so you can style them however you like: plain CSS, your design system or utility frameworks like Tailwind.
{%
Interoperable with Django Templates
Cotton enhances Django templates without replacing them, allowing progressive enhancement while maintaining full use of existing template features.
Enhanced Productivity
Cotton's optional HTML tag-like syntax allows code editors to recognize its components as HTML elements, enabling features like syntax highlighting and automatic tag completion.
Minimal Overhead
Cotton compiles to native Django template tags and caches the result, so it adds virtually no runtime overhead.
Plays well with HTMX and Alpine
Components are just templates, so they drop straight into HTMX swaps and pair naturally with Alpine.js for rich, server-driven interactivity.

Why not just Django templates?

You still can, and Cotton stays fully interoperable with them. But the native tools for reuse get verbose fast. Here is the same idea, the native way and with Cotton.

Native DTL: Verbose & Limited

{# ❌ include: HTML is escaped #}
{% include "card.html" with content="<b>Bold</b>..." %}

{# ❌ extends: only one per template #}
{% extends "card.html" %}
{% block content %}Card 1{% endblock %}
{% extends "card.html" %}
{% block content %}Card 2{% endblock %}

{# ❌ templatetags: needs a .py file #}
{% load card %}
{% card %}

Cotton: Composable & Re-usable

{# ✅ pass rich HTML content #}
<c-card title="First Card">
    <b>Bold</b>, <a href="#">links</a>, anything
</c-card>

{# ✅ reuse unlimited times #}
<c-card title="Card 1">...</c-card>
<c-card title="Card 1">...</c-card>

{# ✅ just an alert.html file, no Python #}
<c-alert type="warning">No Python needed</c-alert>
{# ✅ pass rich HTML content #}
{% cotton card title="First Card" %}
    <b>Bold</b>, <a href="#">links</a>, anything
{% endcotton %}

{# ✅ reuse unlimited times #}
{% cotton card title="Card 1" %}...{% endcotton %}
{% cotton card title="Card 1" %}...{% endcotton %}

{# ✅ just an alert.html file, no Python #}
{% cotton alert type="warning" %}No Python needed{% endcotton %}
next Quickstart