Lightweight reusable template components for Django. An exploratory fork of django-components.
Project description
django-components-lite
A fork of django-components with most features stripped out. A component is a Python class, a Django template, and optional CSS/JS.
If you want the full feature set, use django-components directly.
Attribution
Built on django-components by Emil Stenström, Juro Oravec, and all contributors.
Other Django component libraries
- django-components: the upstream project.
- django-cotton: HTML-like syntax (
<c-card title="..." />), template-only. - django-viewcomponent: Rails-style, one Python class per component.
- slippers: template-only, no Python per component.
- JinjaX: HTML-like component syntax for Jinja2.
django-components-lite is standard Django template tags ({% comp %} / {% slot %} / {% fill %}), one Python class per component, no special template syntax, no monkeypatches, no extension system. The package is ~3000 LOC and can be vendored.
Features
- Component classes with Python logic and Django templates
{% comp %}/{% endcomp %}(and self-closing{% compc %}) template tags- Slots and fills (
{% slot %},{% fill %}) - Component autodiscovery
- Component registry
- Static file handling (JS/CSS)
- Isolated component context
- HTML attribute rendering utilities
Removed vs. upstream
- Extension system
- Built-in components (
DynamicComponent,ErrorFallback) - Component caching
- Provide/Inject system
- Template expressions
- Management commands
- JS/CSS data methods and dependency management
- Type validation (Args/Kwargs/Slots/TemplateData)
on_render()generator system and deferred renderingcontext_behaviorsetting (always isolated, like Django'sinclusion_tag)- Tag formatters
- Component views and URLs
librariessetting andimport_libraries()reload_on_file_changesetting- All deprecated setting aliases
Installation
pip install django-components-lite
Add to INSTALLED_APPS:
INSTALLED_APPS = [
# ...
"django_components_lite",
]
Add the component template loader so component templates get discovered:
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"OPTIONS": {
"loaders": [
"django.template.loaders.filesystem.Loader",
"django.template.loaders.app_directories.Loader",
"django_components_lite.template_loader.Loader",
],
},
},
]
By default, components are discovered in:
- a
components/directory at project root, and - a
components/directory inside each installed app.
To customize, set COMPONENTS:
from django_components_lite import ComponentsSettings
COMPONENTS = ComponentsSettings(
dirs=[BASE_DIR / "components"],
app_dirs=["components"],
)
Defining a component
A component is a Python class with a template:
# components/greeting/greeting.py
from django_components_lite import Component, register
@register("greeting")
class Greeting(Component):
template_name = "greeting.html"
def get_context_data(self, name="World"):
return {"name": name}
<!-- components/greeting/greeting.html -->
{% load component_tags %}
<div class="greeting">
Hello, {{ name }}!
{% slot "extra" %}{% endslot %}
</div>
template_name is resolved relative to the component's Python file, then COMPONENTS.dirs, then Django's template dirs. Use template = "..." for an inline template string.
Static files are declared via a nested Media class (same shape as Django's Forms.Media):
components/greeting/
greeting.py
greeting.html
greeting.css
greeting.js
class Greeting(Component):
template_name = "greeting.html"
class Media:
css = ["greeting.css"]
js = ["greeting.js"]
A <link> or <script> tag is prepended to the output for each entry.
Using a component
From a template:
{% load component_tags %}
{% comp "greeting" name="Django" %}
{% fill "extra" %}<p>Welcome!</p>{% endfill %}
{% endcomp %}
Self-closing form (no body / no fills):
{% compc "greeting" name="Django" %}
Positional arguments are routed to named parameters on get_context_data:
def get_context_data(self, title, body=""): ...
{% comp "card" "My Title" "Body text" %}{% endcomp %}
binds title="My Title" and body="Body text". Mixed positional and keyword args follow Python call semantics. If get_context_data declares *args, positional tag args are forwarded.
From Python:
html = Greeting.render(kwargs={"name": "Django"})
Component.render_to_response(...) returns an HttpResponse.
Slots
Slots are placeholders a parent template fills in.
{% load component_tags %}
<div class="panel">
<header>{% slot "header" %}Default header{% endslot %}</header>
<main>{% slot "body" required %}{% endslot %}</main>
<footer>{% slot "footer" %}{% endslot %}</footer>
</div>
Fill them with {% fill %}:
{% comp "panel" %}
{% fill "header" %}<h2>Custom Header</h2>{% endfill %}
{% fill "body" %}<p>Panel content.</p>{% endfill %}
{% endcomp %}
Content inside {% comp %} without a {% fill %} goes into the slot marked default:
{% slot "content" default %}{% endslot %}
{% comp "panel" %}
This goes into the default slot.
{% endcomp %}
The body of {% slot %} is the fallback when no {% fill %} is provided. To branch on whether a slot was filled, check self.slots:
def get_context_data(self, **kwargs):
return {"has_header": "header" in self.slots}
Settings
from django_components_lite import ComponentsSettings
COMPONENTS = ComponentsSettings(
autodiscover=True,
dirs=[BASE_DIR / "components"],
app_dirs=["components"],
static_files_allowed=[".css", ".js"],
static_files_forbidden=[".html", ".py"],
)
| Setting | Default | Description |
|---|---|---|
autodiscover |
True |
Automatically discover components in app directories |
dirs |
[BASE_DIR / "components"] |
Root-level directories to search for components |
app_dirs |
["components"] |
Subdirectory name within apps to search for components |
static_files_allowed |
CSS, JS, images, fonts | File extensions served as static files |
static_files_forbidden |
.html, .py, etc. |
File extensions never served as static files |
Tag names ({% comp %} / {% endcomp %} / {% compc %}) are not configurable.
API reference
Component
Class attributes:
template_name: path to the template, resolved relative to the component's Python file, thenCOMPONENTS.dirs, then Django template dirs.template: inline template string, used instead oftemplate_name.class Media: nested class withcssandjslists of file paths.
Instance attributes (available in get_context_data):
self.args: positional arguments.self.kwargs: keyword arguments.self.slots: dict of slot name toSlot."name" in self.slotschecks whether a slot was filled.self.context: outer DjangoContextat the call site.self.request: theHttpRequest, orNone.
Methods:
get_context_data(**kwargs): return a dict of context variables. Override with any signature.Component.render(context=None, args=None, kwargs=None, slots=None, request=None): returns rendered HTML.Component.render_to_response(...): same arguments asrender(), returns anHttpResponse. Extra kwargs are forwarded to the response class.
Registration
from django_components_lite import register, registry
@register("name")
class MyComponent(Component): ...
# or manually:
registry.register("name", MyComponent)
registry.unregister("name")
registry.get("name") # component class
registry.all() # dict of all registered components
Template tags
Available after {% load component_tags %}:
| Tag | Description |
|---|---|
{% comp "name" %}...{% endcomp %} |
Render a component, with optional slot fills in the body |
{% compc "name" %} |
Self-closing form, no body, no end tag |
{% slot "name" %}...{% endslot %} |
Define a slot in a component template |
{% fill "name" %}...{% endfill %} |
Fill a slot when using a component |
{% html_attrs attrs defaults key=val %} |
Render an HTML attribute string by merging attrs over defaults, then appending extra kwargs (class/style are space-joined) |
HTML attribute helpers
Used by {% html_attrs %} and available in Python:
from django_components_lite import format_attributes, merge_attributes
merge_attributes({"class": "btn"}, {"class": "btn-primary"})
# -> {"class": "btn btn-primary"}
format_attributes({"class": "btn", "disabled": True})
# -> 'class="btn" disabled'
Changelog
See CHANGELOG.md.
Links
- django-components: upstream
- Issues
License
MIT. See LICENSE.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_components_lite-0.6.1.tar.gz.
File metadata
- Download URL: django_components_lite-0.6.1.tar.gz
- Upload date:
- Size: 68.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
33b6cd79bbc1296faaf7b9d170c3fcb2d21ee94b057c786b17b71387f8874acb
|
|
| MD5 |
a5cdd995cb63a5b0b22abb8e49e732db
|
|
| BLAKE2b-256 |
fa7801f843d933b28ab45d8e8f3977eaf3fc21a10a5a3889051f33cd5dff8d05
|
Provenance
The following attestation bundles were made for django_components_lite-0.6.1.tar.gz:
Publisher:
publish.yml on oliverhaas/django-components-lite
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_components_lite-0.6.1.tar.gz -
Subject digest:
33b6cd79bbc1296faaf7b9d170c3fcb2d21ee94b057c786b17b71387f8874acb - Sigstore transparency entry: 1546827153
- Sigstore integration time:
-
Permalink:
oliverhaas/django-components-lite@c58b0a0db8e37ccc62a46c955b8ff8a2d6e66bfb -
Branch / Tag:
refs/heads/main - Owner: https://github.com/oliverhaas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c58b0a0db8e37ccc62a46c955b8ff8a2d6e66bfb -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file django_components_lite-0.6.1-py3-none-any.whl.
File metadata
- Download URL: django_components_lite-0.6.1-py3-none-any.whl
- Upload date:
- Size: 45.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bf5e89b9b04501feb2f136e19053e3efbb01342036bc408418951b75204ebf6a
|
|
| MD5 |
c37298ca0f535c7248832b60ce42e30b
|
|
| BLAKE2b-256 |
ce3c51fe78127611c044b8a730f2fb93dc9ca011a1f5967fa2baf7734cf48217
|
Provenance
The following attestation bundles were made for django_components_lite-0.6.1-py3-none-any.whl:
Publisher:
publish.yml on oliverhaas/django-components-lite
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_components_lite-0.6.1-py3-none-any.whl -
Subject digest:
bf5e89b9b04501feb2f136e19053e3efbb01342036bc408418951b75204ebf6a - Sigstore transparency entry: 1546827154
- Sigstore integration time:
-
Permalink:
oliverhaas/django-components-lite@c58b0a0db8e37ccc62a46c955b8ff8a2d6e66bfb -
Branch / Tag:
refs/heads/main - Owner: https://github.com/oliverhaas
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c58b0a0db8e37ccc62a46c955b8ff8a2d6e66bfb -
Trigger Event:
workflow_dispatch
-
Statement type: