Components API Reference
On this page
class Component
Base class for stateless components — no events, no lifecycle, just rendering.
from djust.components.base import Component
Methods
__init__(**kwargs)
Pass initial values as keyword arguments. Call super().__init__(**kwargs).
get_context_data() -> dict
Return template context. Override to provide data to the template.
render() -> str
Renders the component to an HTML string. Called automatically by __str__().
Usage:
class Badge(Component):
template = '<span class="badge badge-{{ variant }}">{{ label }}</span>'
def __init__(self, label: str, variant: str = "primary"):
super().__init__(label=label, variant=variant)
self.label = label
self.variant = variant
def get_context_data(self):
return {"label": self.label, "variant": self.variant}
In a LiveView:
def mount(self, request, **kwargs):
self.status_badge = Badge("Active", variant="success")
def get_context_data(self, **kwargs):
return {"status_badge": self.status_badge}
In the template: {{ status_badge }} (calls render() via __str__()). Add |safe ({{ status_badge|safe }}) until #2501's escaping fix lands — without it the markup renders as literal text.
class LiveComponent
Stateful component with its own mount/render lifecycle and event handlers.
from djust.components.base import LiveComponent
Class Attributes
| Attribute | Type | Description |
|---|---|---|
template | str | Inline HTML template |
template_name | str | Path to a template file |
Abstract Methods (must implement)
mount(**kwargs)
Called once when the component is first rendered. Initialize all state here.
def mount(self, **kwargs):
self.count = kwargs.get("initial", 0)
get_context_data() -> dict
Return template context. Called before every render.
def get_context_data(self):
return {"count": self.count}
Instance Methods
trigger_update()
Re-render this component and push the diff to the client. Call after changing state in an event handler.
send_parent(event, data=None)
Send an event to the parent LiveView.
Parameters:
event(str) — Event name stringdata(dict, optional) — Event payload
The parent receives it via handle_component_event().
Critical Template Rule
Put data-component-id="{{ component_id }}" on the component's root element. The client walks up from the element that fired the event to the nearest data-component-id, so events from any descendant are routed to the component. Without it, events route to the parent LiveView:
<div data-component-id="{{ component_id }}">
<button dj-click="increment">+</button>
<span>{{ count }}</span>
</div>
Parent–Child Communication
# Component sends event up:
class CounterWidget(LiveComponent):
@event_handler()
def increment(self, **kwargs):
self.count += 1
self.trigger_update()
self.send_parent("count_changed", {"count": self.count})
# Parent receives it:
class DashboardView(LiveView):
def handle_component_event(self, component_id, event, data):
if event == "count_changed":
self.total = data["count"]
Built-in Components
AlertComponent
from djust.components import AlertComponent
self.alert = AlertComponent(
message="Saved!",
type="success", # "success", "danger", "warning", "info"
dismissible=True,
)
# Methods:
self.alert.show("New message!", "danger")
self.alert.dismiss()
ModalComponent
from djust.components import ModalComponent
self.modal = ModalComponent(
title="Confirm Delete",
body="This cannot be undone.",
show=False,
)
# Methods:
self.modal.show()
self.modal.hide()
TabsComponent
from djust.components import TabsComponent
self.tabs = TabsComponent(
tabs=[
{"id": "tab1", "label": "Overview", "content": "<p>...</p>"},
{"id": "tab2", "label": "Settings", "content": "<p>...</p>", "badge": "3"},
],
active="tab1",
)
# Methods:
self.tabs.activate_tab("tab2")
TableComponent
from djust.components import TableComponent
self.table = TableComponent(
columns=[
{"key": "name", "label": "Name", "sortable": True},
{"key": "email", "label": "Email"},
],
rows=[
{"name": "Alice", "email": "alice@example.com"},
],
striped=True,
hoverable=True,
)
A sortable column header carries aria-sort (none / ascending /
descending) and a visual mark in the framework's icon convention —
Bootstrap Icons classes on bootstrap5 (bi-arrow-down-up, bi-caret-up-fill,
bi-caret-down-fill; load the Bootstrap Icons stylesheet), the vendored
heroicons SVG on tailwind, and ⇅ / ▲ / ▼ on plain.
selectable=True adds a checkbox per row and one in the header. A row is
identified by its row_key value (default "id"), stored as a string in
selected_rows — the same convention as {% data_table %}:
self.table = TableComponent(columns=..., rows=..., selectable=True, row_key="id")
# after the user ticks two rows:
self.table.selected_rows # ["3", "7"]
The row checkbox toggles that row (toggle_row); the header checkbox selects
every visible row, or clears the selection when every visible row is
already selected (toggle_all).
filterable=True adds a global filter input above the table: rows stay visible
when any column's string value contains the query, case-insensitively.
{"filterable": True} on a column adds a filter input under that header that
narrows on that column alone. Both compose (every filter must match), and they
compose with the sort: rows are filtered, then sorted. The rows you passed are
never narrowed — clearing an input restores them. The conventions mirror
{% data_table %} / DataTableMixin (icontains, an empty value removes the
filter, select-all is the post-filter set):
self.table = TableComponent(
columns=[
{"key": "name", "label": "Name", "sortable": True, "filterable": True},
{"key": "email", "label": "Email"},
],
rows=...,
filterable=True,
)
# after the user types:
self.table.filter_query # "ali" — the global input (filter_rows)
self.table.column_filters # {"name": "al"} — per column (filter_column)
The inputs are dj-input controls debounced at 300 ms (dj-debounce="300"),
routed to the component with data-component-id, and labelled
(aria-label="Search table" / aria-label="Filter <label>").
Table anatomy and CSS classes
Use additive class hooks to customize the table without replacing its renderer.
For Bootstrap, table_class="align-middle caption-top" enables vertical alignment
and a top caption; thead_class="table-dark" styles the header. Supply utility
classes appropriate to your stylesheet when using Tailwind or plain rendering.
self.table = TableComponent(
columns=[{"key": "name", "label": "Name"}, {"key": "count", "label": "Count"}],
rows=[{"name": "Alice", "count": 3}],
table_class="align-middle caption-top",
thead_class="table-dark",
caption="Items by owner",
caption_class="text-muted",
footer={"name": "Total", "count": 3},
tfoot_class="table-light",
)
| Option | Purpose | Default |
|---|---|---|
table_class | Classes appended to the framework's table classes | "" |
thead_class, tbody_class, tfoot_class | Classes on the respective table sections | "" |
caption | Text in a semantic <caption> before the header | None (omitted) |
caption_class | Classes on the caption | "" |
footer | One summary row, a mapping keyed like the data rows | None (omitted) |
Caption and footer text and all class strings are HTML-escaped. Footer cells follow the declared column order; missing keys render empty cells, and selection adds an empty alignment cell. The footer is a supplied summary, not an automatically calculated total, and is not sorted, filtered, or selected with the data rows.
PaginationComponent
from djust.components import PaginationComponent
self.pagination = PaginationComponent(
current_page=1,
total_pages=10,
on_page_change="go_to_page", # event handler name
)
ProgressComponent
from djust.components import ProgressComponent
self.progress = ProgressComponent(value=65, max_value=100, custom_label="65%")
ForeignKeySelect / ManyToManySelect
from djust.components.forms import ForeignKeySelect, ManyToManySelect
self.author_select = ForeignKeySelect(
name="author",
queryset=Author.objects.all(),
label_field="name",
searchable=True,
search_fields=["name", "email"],
)
Component Registry
from djust.components import register_component, get_component, list_components
# Register a custom component globally
register_component("my_widget", MyWidgetComponent)
# Retrieve by name
cls = get_component("my_widget")
# List all registered components
registry = list_components() # {'alert': AlertComponent, 'modal': ModalComponent, ...}
Stateless UI Components
Quick-use display components. No event handling.
from djust.components.ui import Badge, Button, Card, Alert
badge = Badge(text="New", variant="success")
button = Button(text="Click me", variant="primary", disabled=False)
card = Card(body="Content here", header="My Card")
Full list:
Badge, Button, Card, Alert, Modal, Accordion, Avatar, Breadcrumb,
Checkbox, Divider, Dropdown, Icon, Input, ListGroup, NavBar,
Pagination, Progress, Radio, Range, Select, Spinner, Switch,
Table, Tabs, TextArea, Toast, Tooltip
See Also
Markdown editor
See the Markdown Editor guide for optional Visual/Markdown editing, native form integration, asset loading, theme variables and editing limitations.