Welcome to Django Components
django-components
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:
<div class="calendar">
Today's date is <span>{{ date }}</span>
</div>
from django_components import Component
class Calendar(Component):
template_file = "calendar.html"
Or a combination of Django template, Python, CSS, and Javascript:
<div class="calendar">
Today's date is <span>{{ date }}</span>
</div>
document.querySelector(".calendar").onclick = () => {
alert("Clicked calendar!");
};
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:
And this is what gets rendered:
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
is designed for flexibility, making working with templates a breeze.
It extends Django's template tags syntax with:
- Literal lists and dictionaries in the template
- Self-closing tags
{% mytag / %}
- Multi-line template tags
- Spread operator
...
to dynamically pass args or kwargs into the template tag - Template tags inside literal strings like
"{{ first_name }} {{ last_name }}"
- Pass dictonaries by their key-value pairs
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"
/ %}
You too can define template tags with these features by using @template_tag()
or BaseNode
.
Read more on Custom template tags.
Full programmatic access¤
When you render a component, you can access everything about the component:
- Component input: args, kwargs, slots and context
- Component's template, CSS and JS
- Django's context processors
- Unique render ID
class Table(Component):
js_file = "table.js"
css_file = "table.css"
template = """
<div class="table">
<span>{{ variable }}</span>
</div>
"""
def get_context_data(self, var1, var2, variable, another, **attrs):
# Access component's ID
assert self.id == "djc1A2b3c"
# Access component's inputs and slots
assert self.input.args == (123, "str")
assert self.input.kwargs == {"variable": "test", "another": 1}
footer_slot = self.input.slots["footer"]
some_var = self.input.context["some_var"]
# Access the request object and Django's context processors, if available
assert self.request.GET == {"query": "something"}
assert self.context_processors_data['user'].username == "admin"
return {
"variable": variable,
}
# Access component's HTML / JS / CSS
Table.template
Table.js
Table.css
# Render the component
rendered = Table.render(
kwargs={"variable": "test", "another": 1},
args=(123, "str"),
slots={"footer": "MY_FOOTER"},
)
Granular HTML attributes¤
Use the {% html_attrs %}
template tag to render HTML attributes.
It supports:
- Defining attributes as whole dictionaries or keyword arguments
- Merging attributes from multiple sources
- Boolean attributes
- Appending attributes
- Removing attributes
- Defining default attributes
{% html_attrs %}
offers a Vue-like granular control for class
and style
HTML attributes, where you can use a dictionary to manage each class name or style property separately.
{% html_attrs
style="text-align: center; background-color: blue;"
style={
"background-color": "green",
"color": None,
"width": False,
}
style="position: absolute; height: 12px;"
%}
Read more about HTML attributes.
HTML fragment support¤
django-components
makes integration with HTMX, AlpineJS or jQuery easy by allowing components to be rendered as HTML fragments:
-
Components's JS and CSS files are loaded automatically when the fragment is inserted into the DOM.
-
Components can be exposed as Django Views with
get()
,post()
,put()
,patch()
,delete()
methods -
Automatically create an endpoint for a component with
Component.Url.public
# components/calendar/calendar.py
@register("calendar")
class Calendar(Component):
template_file = "calendar.html"
# Register Component with `urlpatterns`
class Url:
public = True
# Define handlers
class View:
def get(self, request, *args, **kwargs):
page = request.GET.get("page", 1)
return self.component.render_to_response(
request=request,
kwargs={
"page": page,
},
)
def get_context_data(self, page):
return {
"page": page,
}
# Get auto-generated URL for the component
url = get_component_url(Calendar)
# Or define explicit URL in urls.py
path("calendar/", Calendar.as_view())
Provide / Inject¤
django-components
supports the provide / inject pattern, similarly to React's Context Providers or Vue's provide / inject:
- Use the
{% provide %}
tag to provide data to the component tree - Use the
Component.inject()
method to inject data into the component
Read more about Provide / Inject.
@register("header")
class Header(Component):
template = "..."
def get_context_data(self, *args, **kwargs):
theme = self.inject("theme").variant
return {
"theme": theme,
}
Static type hints¤
Components API is fully typed, and supports static type hints.
To opt-in to static type hints, define types for component's args, kwargs, slots, and more:
from typing import NotRequired, Tuple, TypedDict, SlotContent, SlotFunc
from django_components import Component
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
- Add custom CLI commands
- Add custom URLs
Some of the extensions include:
- Component caching
- Django View integration
- Component defaults
- Pydantic integration (input validation)
Some of the planned extensions include:
- AlpineJS integration
- Storybook integration
- Component-level benchmarking with asv
Caching¤
- Components can be cached using Django's cache framework.
- Caching rules can be configured on a per-component basis.
- Components are cached based on their input. Or you can write custom caching logic.
from django_components import Component
class MyComponent(Component):
class Cache:
enabled = True
ttl = 60 * 60 * 24 # 1 day
def hash(self, *args, **kwargs):
return hash(f"{json.dumps(args)}:{json.dumps(kwargs)}")
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 django_components.testing import djc_test
from components.my_table import MyTable
@djc_test
def test_my_table():
rendered = MyTable.render(
kwargs={
"title": "My table",
},
)
assert rendered == "<table>My table</table>"
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.

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):
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. Head over to the Community examples to see some examples.
Contributing and development¤
Get involved or sponsor this project - See here
Running django-components locally for development - See here