Skip to main content

A way to create simple reusable template components in Django.

Project description

django-components

PyPI - Version PyPI - Python Version PyPI - License PyPI - Downloads GitHub Actions Workflow Status asv

Read the full documentation

django-components is a modular and extensible UI framework for Django.

It combines Django's templating system with the modularity seen in modern frontend frameworks like Vue or React.

With django-components you can support Django projects small and large without leaving the Django ecosystem.

Quickstart

A component in django-components can be as simple as a Django template and Python code to declare the component:

{# components/calendar/calendar.html #}
<div class="calendar">
  Today's date is <span>{{ date }}</span>
</div>
# components/calendar/calendar.html
from django_components import Component

class Calendar(Component):
    template_file = "calendar.html"

Or a combination of Django template, Python, CSS, and Javascript:

{# components/calendar/calendar.html #}
<div class="calendar">
  Today's date is <span>{{ date }}</span>
</div>
/* components/calendar/calendar.css */
.calendar {
  width: 200px;
  background: pink;
}
/* components/calendar/calendar.js */
document.querySelector(".calendar").onclick = () => {
  alert("Clicked calendar!");
};
# components/calendar/calendar.py
from django_components import Component

class Calendar(Component):
    template_file = "calendar.html"
    js_file = "calendar.js"
    css_file = "calendar.css"

    def get_context_data(self, date):
        return {"date": date}

Use the component like this:

{% component "calendar" date="2024-11-06" %}{% endcomponent %}

And this is what gets rendered:

<div class="calendar-component">
  Today's date is <span>2024-11-06</span>
</div>

Read on to learn about all the exciting details and configuration possibilities!

(If you instead prefer to jump right into the code, check out the example project)

Features

Modern and modular UI

  • Create self-contained, reusable UI elements.
  • Each component can include its own HTML, CSS, and JS, or additional third-party JS and CSS.
  • HTML, CSS, and JS can be defined on the component class, or loaded from files.
from django_components import Component

@register("calendar")
class Calendar(Component):
    template = """
        <div class="calendar">
            Today's date is
            <span>{{ date }}</span>
        </div>
    """

    css = """
        .calendar {
            width: 200px;
            background: pink;
        }
    """

    js = """
        document.querySelector(".calendar")
            .addEventListener("click", () => {
                alert("Clicked calendar!");
            });
    """

    # Additional JS and CSS
    class Media:
        js = ["https://cdn.jsdelivr.net/npm/htmx.org@2.1.1/dist/htmx.min.js"]
        css = ["bootstrap/dist/css/bootstrap.min.css"]

    # Variables available in the template
    def get_context_data(self, date):
        return {
            "date": date
        }

Composition with slots

  • Render components inside templates with {% component %} tag.
  • Compose them with {% slot %} and {% fill %} tags.
  • Vue-like slot system, including scoped slots.
{% component "Layout"
    bookmarks=bookmarks
    breadcrumbs=breadcrumbs
%}
    {% fill "header" %}
        <div class="flex justify-between gap-x-12">
            <div class="prose">
                <h3>{{ project.name }}</h3>
            </div>
            <div class="font-semibold text-gray-500">
                {{ project.start_date }} - {{ project.end_date }}
            </div>
        </div>
    {% endfill %}

    {# Access data passed to `{% slot %}` with `data` #}
    {% fill "tabs" data="tabs_data" %}
        {% component "TabItem" header="Project Info" %}
            {% component "ProjectInfo"
                project=project
                project_tags=project_tags
                attrs:class="py-5"
                attrs:width=tabs_data.width
            / %}
        {% endcomponent %}
    {% endfill %}
{% endcomponent %}

Extended template tags

django-components extends Django's template tags syntax with:

  • Literal lists and dictionaries in template tags
  • Self-closing tags {% mytag / %}
  • Multi-line template tags
  • Spread operator ... to dynamically pass args or kwargs into the template tag
  • Nested template tags like "{{ first_name }} {{ last_name }}"
  • Flat definition of dictionary keys attr:key=val
{% component "table"
    ...default_attrs
    title="Friend list for {{ user.name }}"
    headers=["Name", "Age", "Email"]
    data=[
        {
            "name": "John"|upper,
            "age": 30|add:1,
            "email": "john@example.com",
            "hobbies": ["reading"],
        },
        {
            "name": "Jane"|upper,
            "age": 25|add:1,
            "email": "jane@example.com",
            "hobbies": ["reading", "coding"],
        },
    ],
    attrs:class="py-4 ma-2 border-2 border-gray-300 rounded-md"
/ %}

HTML fragment support

django-components makes intergration with HTMX, AlpineJS or jQuery easy by allowing components to be rendered as HTML fragments:

  • Components's JS and CSS is loaded automatically when the fragment is inserted into the DOM.

  • Expose components as views with get, post, put, patch, delete methods

# components/calendar/calendar.py
@register("calendar")
class Calendar(Component):
    template_file = "calendar.html"

    def get(self, request, *args, **kwargs):
        page = request.GET.get("page", 1)
        return self.render_to_response(
            kwargs={
                "page": page,
            }
        )

    def get_context_data(self, page):
        return {
            "page": page,
        }

# urls.py
path("calendar/", Calendar.as_view()),

Type hints

Opt-in to type hints by defining types for component's args, kwargs, slots, and more:

from typing import NotRequired, Tuple, TypedDict, SlotContent, SlotFunc

ButtonArgs = Tuple[int, str]

class ButtonKwargs(TypedDict):
    variable: str
    another: int
    maybe_var: NotRequired[int] # May be omitted

class ButtonData(TypedDict):
    variable: str

class ButtonSlots(TypedDict):
    my_slot: NotRequired[SlotFunc]
    another_slot: SlotContent

ButtonType = Component[ButtonArgs, ButtonKwargs, ButtonSlots, ButtonData, JsData, CssData]

class Button(ButtonType):
    def get_context_data(self, *args, **kwargs):
        self.input.args[0]  # int
        self.input.kwargs["variable"]  # str
        self.input.slots["my_slot"]  # SlotFunc[MySlotData]

        return {}  # Error: Key "variable" is missing

When you then call Button.render() or Button.render_to_response(), you will get type hints:

Button.render(
    # Error: First arg must be `int`, got `float`
    args=(1.25, "abc"),
    # Error: Key "another" is missing
    kwargs={
        "variable": "text",
    },
)

Extensions

Django-components functionality can be extended with "extensions". Extensions allow for powerful customization and integrations. They can:

  • Tap into lifecycle events, such as when a component is created, deleted, or registered.
  • Add new attributes and methods to the components under an extension-specific nested class.

Some of the planned extensions include:

  • Caching
  • AlpineJS integration
  • Storybook integration
  • Pydantic validation
  • Component-level benchmarking with asv

Simple testing

  • Write tests for components with @djc_test decorator.
  • The decorator manages global state, ensuring that tests don't leak.
  • If using pytest, the decorator allows you to parametrize Django or Components settings.
  • The decorator also serves as a stand-in for Django's @override_settings.
from djc_test import djc_test

from components.my_component import MyTable

@djc_test
def test_my_table():
    rendered = MyTable.render(
        kwargs={
            "title": "My table",
        },
    )
    assert rendered == "<table>My table</table>"

Handle large projects with ease

  • Components can be infinitely nested.
  • (Soon) Optimize performance with component-level caching

Debugging features

  • Visual component inspection: Highlight components and slots directly in your browser.
  • Detailed tracing logs to supply AI-agents with context: The logs include component and slot names and IDs, and their position in the tree.
Component debugging visualization showing slot highlighting

Sharing components

  • Install and use third-party components from PyPI

  • Or publish your own "component registry"

  • Highly customizable - Choose how the components are called in the template (and more):

    {% component "calendar" date="2024-11-06" %}
    {% endcomponent %}
    
    {% calendar date="2024-11-06" %}
    {% endcalendar %}
    

Other features

  • Vue-like provide / inject system
  • Format HTML attributes with {% html_attrs %}

Documentation

Read the full documentation here.

... or jump right into the code, check out the example project.

Performance

Our aim is to be at least as fast as Django templates.

As of 0.130, django-components is ~4x slower than Django templates.

Render time
django 68.9±0.6ms
django-components 259±4ms

See the full performance breakdown for more information.

Release notes

Read the Release Notes to see the latest features and fixes.

Community examples

One of our goals with django-components is to make it easy to share components between projects. If you have a set of components that you think would be useful to others, please open a pull request to add them to the list below.

Contributing and development

Get involved or sponsor this project - See here

Running django-components locally for development - See here

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_components-0.134.tar.gz (157.6 kB view details)

Uploaded Source

Built Distribution

django_components-0.134-py3-none-any.whl (178.3 kB view details)

Uploaded Python 3

File details

Details for the file django_components-0.134.tar.gz.

File metadata

  • Download URL: django_components-0.134.tar.gz
  • Upload date:
  • Size: 157.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for django_components-0.134.tar.gz
Algorithm Hash digest
SHA256 7b73e86cab0e127cad0421742c286bf8d987923ea541c74f2a0891d65fb80072
MD5 4e53c7e7054cb5e718434d426d8226a1
BLAKE2b-256 4a00f003f0abd2990d0327002f15debe9c1eb1d8ab1af04fef5db925f9e4272b

See more details on using hashes here.

File details

Details for the file django_components-0.134-py3-none-any.whl.

File metadata

File hashes

Hashes for django_components-0.134-py3-none-any.whl
Algorithm Hash digest
SHA256 985fa8c3536b6b82b3d41ccf7e4b3189b4ecd6ec429b3d60374c15c702d4f901
MD5 b0aea8f6cb88d32ef671a197455a7223
BLAKE2b-256 4a78b7bb7154e8af45cfa147605c740375e9c0e0a530ba493818bf4df3efeec7

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page