Explore all Django Rust Live components with live, interactive examples. All components support Bootstrap 5, Tailwind CSS, and plain HTML rendering.
Python Code:
from django_rust_live.components import AlertComponent
# In your mount() method:
self.alert_success = AlertComponent(
message="Operation completed successfully!",
type="success", # info, success, warning, danger, error
dismissible=True
)
self.alert_info = AlertComponent(
message="Here's some helpful information.",
type="info",
icon=True
)
self.alert_warning = AlertComponent(
message="Warning: Please review your changes.",
type="warning",
dismissible=True
)
# Event handler for dismissing alerts (automatically routes to correct component):
def dismiss(self, component_id: str = None):
"""Dismiss event automatically routes to the component by attribute name"""
if component_id and hasattr(self, component_id):
component = getattr(self, component_id)
if hasattr(component, 'dismiss'):
component.dismiss()
# Update message dynamically:
def show_alert(self):
self.alert_success.set_message("Updated message!")
self.alert_success.show()
Template:
{{ alert_success.render }}
{{ alert_info.render }}
{{ alert_warning.render }}
Button click count: 0
Python Code:
from django_rust_live.components import ButtonComponent
# In your mount() method:
self.button_primary = ButtonComponent(
label="Primary Button",
variant="primary", # primary, secondary, success, danger, warning, info
size="md", # sm, md, lg
on_click="handle_button_click" # Method name to call
)
self.button_with_icon = ButtonComponent(
label="Success",
variant="success",
icon="✓", # Add icon (emoji or HTML)
outline=True # Outline style button
)
# Event handler:
def handle_button_click(self):
self.button_click_count += 1
# State changes automatically trigger re-render
Template:
{{ button_primary.render }}
{{ button_with_icon.render }}
Python Code:
from django_rust_live.components import BadgeComponent
# In your mount() method:
self.badge_primary = BadgeComponent(
text="Primary",
variant="primary" # primary, secondary, success, danger, warning, info
)
self.badge_success = BadgeComponent(
text="Active",
variant="success",
pill=True # Rounded pill style
)
self.badge_dismissible = BadgeComponent(
text="Python",
variant="info",
dismissible=True, # Add close button
on_dismiss="dismiss_tag" # Method to call when dismissed
)
# Event handler:
def dismiss_tag(self):
self.badge_dismissible.dismiss()
Template:
{{ badge_primary.render }}
{{ badge_success.render }}
{{ badge_dismissible.render }}
Python Code:
from django_rust_live.components import DropdownComponent
# In your mount() method:
self.dropdown_actions = DropdownComponent(
label="Actions",
variant="primary",
items=[
{'text': 'Edit', 'action': 'edit_item', 'icon': '✏️'},
{'text': 'Delete', 'action': 'delete_item', 'icon': '🗑️', 'variant': 'danger'},
{'divider': True}, # Add separator line
{'text': 'Archive', 'action': 'archive_item'},
]
)
self.dropdown_split = DropdownComponent(
label="Split Dropdown",
variant="success",
split=True, # Split button style
items=[
{'text': 'Action 1', 'action': 'action1'},
{'text': 'Action 2', 'action': 'action2'},
]
)
# Event handlers for dropdown items:
def edit_item(self):
# Handle edit action
pass
def delete_item(self):
# Handle delete action
pass
Template:
{{ dropdown_actions.render }}
{{ dropdown_split.render }}
This is a simple card component with a title and body text.
Python Code:
from django_rust_live.components import CardComponent
# In your mount() method:
self.card_basic = CardComponent(
title="Basic Card",
body="This is a simple card component with a title and body text.",
variant="default" # default, primary, success, info, warning, danger
)
self.card_with_footer = CardComponent(
title="Featured Card",
body="This card has a footer with additional information.",
footer="Last updated 3 mins ago",
variant="primary"
)
# Cards can also include custom HTML in body/footer
self.card_custom = CardComponent(
title="Custom Card",
body="<p>You can include <strong>HTML</strong> content.</p>",
footer="<button class='btn btn-sm btn-primary'>Action</button>"
)
Template:
{{ card_basic.render }}
{{ card_with_footer.render }}
Modal opened: 0 time(s)
Python Code:
from django_rust_live.components import ModalComponent
# In your mount() method:
self.modal_example = ModalComponent(
title="Example Modal",
body="This is a modal dialog with customizable content.",
show=False, # Initially hidden
size="lg" # sm, md, lg, xl
)
self.modal_open_count = 0
# Event handlers:
def show_modal(self):
"""Show the modal and update its content"""
self.modal_open_count += 1
self.modal_example.set_body(f"This modal has been opened {self.modal_open_count} time(s).")
self.modal_example.show()
def close_modal(self):
"""Close the modal"""
self.modal_example.hide()
# Update modal content dynamically:
def update_modal_content(self):
self.modal_example.set_title("New Title")
self.modal_example.set_body("<p>Updated content with <strong>HTML</strong></p>")
Template:
<!-- Trigger button -->
<button class="btn btn-primary" @click="show_modal">Open Modal</button>
<!-- Modal component -->
{{ modal_example.render }}
Simple Progress
Striped & Animated
Custom Label
Python Code:
from django_rust_live.components import ProgressComponent
# In your mount() method:
self.progress_simple = ProgressComponent(
value=45, # 0-100
variant="primary", # primary, success, info, warning, danger
show_label=True # Show percentage label
)
self.progress_striped = ProgressComponent(
value=65,
variant="success",
striped=True, # Add striped pattern
animated=True, # Animate the stripes
show_label=True
)
self.progress_custom = ProgressComponent(
value=30,
variant="warning",
custom_label="Processing...", # Custom text instead of percentage
striped=True
)
self.current_progress = 45
# Event handlers:
def increment_progress(self):
"""Increment progress bar value"""
if self.current_progress < 100:
self.current_progress += 10
self.progress_simple.set_value(self.current_progress)
self.progress_striped.set_value(min(self.current_progress + 20, 100))
def reset_progress(self):
"""Reset progress bars to 0"""
self.current_progress = 0
self.progress_simple.reset()
self.progress_striped.reset()
Template:
{{ progress_simple.render }}
{{ progress_striped.render }}
{{ progress_custom.render }}
Python Code:
from django_rust_live.components import SpinnerComponent
# In your mount() method:
self.spinner_border = SpinnerComponent(
variant="primary", # primary, success, info, warning, danger, secondary
size="md", # sm, md, lg
type="border", # border (default) or grow
label="Loading..." # Screen reader text
)
self.spinner_grow = SpinnerComponent(
variant="success",
size="sm",
type="grow" # Growing spinner animation
)
# Use spinners to show loading states:
def load_data(self):
self.is_loading = True
# ... fetch data ...
self.is_loading = False
Template:
<!-- Show spinner while loading -->
{% if is_loading %}
{{ spinner_border.render }}
{% else %}
<!-- Your content here -->
{% endif %}
<!-- Or inline with buttons -->
{{ spinner_grow.render }}
Welcome to the Home tab!
This content is loaded immediately.
User profile information goes here.
Your messages appear here.
Configure your settings.
Python Code:
from django_rust_live.components import TabsComponent
# In your mount() method:
self.tabs_example = TabsComponent(
tabs=[
{
'id': 'home',
'label': 'Home',
'content': '<p>Welcome to the Home tab!</p>'
},
{
'id': 'profile',
'label': 'Profile',
'content': '<p>User profile information goes here.</p>'
},
{
'id': 'messages',
'label': 'Messages',
'content': '<p>Your messages appear here.</p>',
'badge': '5' # Add notification badge
},
{
'id': 'settings',
'label': 'Settings',
'content': '<p>Configure your settings.</p>',
'disabled': True # Disable tab
},
],
active='home', # Initially active tab
variant='tabs' # 'tabs' or 'pills'
)
# Change active tab programmatically:
def switch_to_profile(self):
self.tabs_example.set_active('profile')
Template:
{{ tabs_example.render }}
Click column headers to sort
| ID | Name | Role | Status | |
|---|---|---|---|---|
| 1 | Alice Johnson | alice@example.com | Admin | active |
| 2 | Bob Smith | bob@example.com | User | active |
| 3 | Charlie Brown | charlie@example.com | User | inactive |
| 4 | Diana Prince | diana@example.com | Moderator | active |
| 5 | Eve Wilson | eve@example.com | User | active |
Python Code:
from django_rust_live.components import TableComponent
# In your mount() method:
self.table_users = TableComponent(
columns=[
{'key': 'id', 'label': 'ID', 'sortable': True},
{'key': 'name', 'label': 'Name', 'sortable': True},
{'key': 'email', 'label': 'Email', 'sortable': True},
{'key': 'role', 'label': 'Role', 'badge': True}, # Render as badge
{'key': 'status', 'label': 'Status', 'badge': True},
],
rows=[
{'id': 1, 'name': 'Alice Johnson', 'email': 'alice@example.com',
'role': 'Admin', 'status': 'active'},
{'id': 2, 'name': 'Bob Smith', 'email': 'bob@example.com',
'role': 'User', 'status': 'active'},
{'id': 3, 'name': 'Charlie Brown', 'email': 'charlie@example.com',
'role': 'User', 'status': 'inactive'},
],
striped=True, # Alternating row colors
hoverable=True, # Highlight row on hover
bordered=True # Add borders
)
# Can also use Django QuerySet:
# rows = User.objects.all().values('id', 'name', 'email', 'role', 'status')
# self.table_users = TableComponent(columns=columns, rows=rows)
Template:
{{ table_users.render }}
Python Code:
from django_rust_live.components import PaginationComponent
# In your mount() method:
self.pagination_basic = PaginationComponent(
current_page=3,
total_pages=10,
show_page_info=True, # Show "Page 3 of 10"
alignment='center' # left, center, right
)
self.pagination_large = PaginationComponent(
current_page=1,
total_items=250, # Total number of items
items_per_page=25, # Items shown per page
size='lg', # sm, md, lg
on_page_change='handle_page_change' # Event handler
)
# Event handler:
def handle_page_change(self, page: int):
"""Called when user clicks a page number"""
self.current_page = page
# Fetch new data for this page
self.load_data(page)
# Using with Django Paginator:
from django.core.paginator import Paginator
def mount(self, request):
items = MyModel.objects.all()
paginator = Paginator(items, 25)
page_number = request.GET.get('page', 1)
page_obj = paginator.get_page(page_number)
self.pagination = PaginationComponent(
current_page=page_obj.number,
total_pages=paginator.num_pages,
on_page_change='change_page'
)
Template:
{{ pagination_basic.render }}
{{ pagination_large.render }}
This demonstrates how components can be composed together in complex UIs.
Shows LiveView initialization, components, event handlers, and template integration
# views.py
from django_rust_live import LiveView
from django_rust_live.components import ButtonComponent, AlertComponent
class CounterView(LiveView):
template_name = "counter.html"
def mount(self, request):
"""Called when the view first loads - initialize state here"""
# State variables - these are automatically synced with the template
self.counter = 0
self.message = ""
# Create interactive components
# on_click="increment" calls the increment() method below
self.increment_btn = ButtonComponent(
label="Increment Counter",
variant="primary",
on_click="increment"
)
self.reset_btn = ButtonComponent(
label="Reset",
variant="secondary",
on_click="reset"
)
# Alert component to show messages
self.alert = AlertComponent(
message=self.message,
variant="success",
dismissible=True
)
def increment(self):
"""Called when increment button is clicked - updates sent via WebSocket"""
self.counter += 1
self.message = f"Counter incremented to {self.counter}"
# State changes automatically trigger a re-render
def reset(self):
"""Reset counter to zero"""
self.counter = 0
self.message = "Counter reset"
Template: Shows how to use the view state and components
<!-- counter.html -->
{% extends "base.html" %}
{% block content %}
<!-- All interactive content must be inside data-liveview-root -->
<div data-liveview-root>
<div class="card">
<div class="card-body">
<!-- Access state variables directly from the view -->
<h2>Current Count: {{ counter }}</h2>
<!-- Render components created in mount() -->
<div class="mt-3">
{{ increment_btn.render }}
{{ reset_btn.render }}
</div>
<!-- Conditionally show alert when there's a message -->
{% if message %}
<div class="mt-3">
{{ alert.render }}
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}
Shows Django form integration with live field validation and error display
# views.py
from django import forms
from django_rust_live import LiveView, FormMixin
class ContactForm(forms.Form):
"""Standard Django form - works with LiveView automatically"""
name = forms.CharField(
max_length=100,
required=True,
help_text="Your full name"
)
email = forms.EmailField(
required=True,
help_text="We'll never share your email"
)
message = forms.CharField(
widget=forms.Textarea,
min_length=10,
help_text="At least 10 characters"
)
class ContactFormView(FormMixin, LiveView):
"""FormMixin adds automatic form handling and validation"""
form_class = ContactForm
template_name = "contact.html"
def mount(self, request):
"""Initialize form state"""
self.success_message = ""
self.error_message = ""
def validate_field(self, field_name, value):
"""Called when a field loses focus (@change event)
Returns errors in real-time before form submission"""
# Validate single field and return errors
pass
def form_valid(self, form):
"""Called when form is submitted and all validation passes"""
# Access cleaned data
name = form.cleaned_data['name']
email = form.cleaned_data['email']
message = form.cleaned_data['message']
# Process the data (send email, save to DB, etc.)
# send_email(email, message)
self.success_message = f"Thanks {name}! We'll be in touch."
form = ContactForm() # Reset form
def form_invalid(self, form):
"""Called when validation fails
Errors are automatically shown in the template"""
self.error_message = "Please fix the errors below"
Template: Form with live validation and error display
<!-- contact.html -->
{% extends "base.html" %}
{% block content %}
<div data-liveview-root>
<!-- Success/Error Messages -->
{% if success_message %}
<div class="alert alert-success">{{ success_message }}</div>
{% endif %}
{% if error_message %}
<div class="alert alert-danger">{{ error_message }}</div>
{% endif %}
<!-- @submit calls form_valid() or form_invalid() based on validation -->
<form @submit="submit_form">
<!-- Name Field -->
<div class="mb-3">
<label>Name</label>
<input
type="text"
name="name"
class="form-control {% if field_errors.name %}is-invalid{% endif %}"
value="{{ form_data.name }}"
@change="validate_field"
data-field="name"
/>
<!-- Errors shown in real-time as user types -->
{% if field_errors.name %}
<div class="invalid-feedback d-block">
{% for error in field_errors.name %}
{{ error }}
{% endfor %}
</div>
{% endif %}
</div>
<!-- Email Field (similar structure) -->
<div class="mb-3">
<label>Email</label>
<input
type="email"
name="email"
class="form-control {% if field_errors.email %}is-invalid{% endif %}"
value="{{ form_data.email }}"
@change="validate_field"
data-field="email"
/>
{% if field_errors.email %}
<div class="invalid-feedback d-block">
{% for error in field_errors.email %}{{ error }}{% endfor %}
</div>
{% endif %}
</div>
<button type="submit" class="btn btn-primary">Send Message</button>
</form>
</div>
{% endblock %}
Shows handling events with parameters, working with lists, and dynamic rendering
# views.py
from django_rust_live import LiveView
class TodoListView(LiveView):
template_name = "todos.html"
def mount(self, request):
"""Initialize the todo list"""
self.todos = [
{"id": 1, "text": "Learn Django Rust Live", "done": False},
{"id": 2, "text": "Build an app", "done": False},
]
self.next_id = 3 # Track next ID for new todos
self.new_todo_text = "" # Bind to input field
def add_todo(self):
"""Add new todo from form submission
Form data is automatically available in self.form_data"""
text = self.new_todo_text.strip()
if text:
self.todos.append({
"id": self.next_id,
"text": text,
"done": False
})
self.next_id += 1
self.new_todo_text = "" # Clear input
def toggle_todo(self, todo_id):
"""Toggle completion status - receives ID from data-todo-id"""
for todo in self.todos:
if todo["id"] == int(todo_id):
todo["done"] = not todo["done"]
break
def delete_todo(self, todo_id):
"""Delete todo by ID"""
self.todos = [t for t in self.todos if t["id"] != int(todo_id)]
def get_context_data(self, **kwargs):
"""Add computed values to template context"""
context = super().get_context_data(**kwargs)
context["total_count"] = len(self.todos)
context["done_count"] = sum(1 for t in self.todos if t["done"])
context["pending_count"] = context["total_count"] - context["done_count"]
return context
Template: Dynamic list with event parameters
<!-- todos.html -->
{% extends "base.html" %}
{% block content %}
<div data-liveview-root>
<h2>My Todos</h2>
<!-- Stats from get_context_data() -->
<p>{{ done_count }} done, {{ pending_count }} pending ({{ total_count }} total)</p>
<!-- Add new todo form -->
<form @submit="add_todo" class="mb-4">
<div class="input-group">
<input
type="text"
name="new_todo_text"
class="form-control"
placeholder="Add a new task..."
value="{{ new_todo_text }}"
/>
<button type="submit" class="btn btn-primary">Add</button>
</div>
</form>
<!-- Todo list - loops through self.todos -->
<ul class="list-group">
{% for todo in todos %}
<li class="list-group-item d-flex align-items-center">
<!-- Checkbox to toggle - passes todo.id via data attribute -->
<input
type="checkbox"
class="form-check-input me-2"
{% if todo.done %}checked{% endif %}
@change="toggle_todo"
data-todo-id="{{ todo.id }}"
/>
<!-- Todo text with strikethrough if done -->
<span class="{% if todo.done %}text-decoration-line-through{% endif %}">
{{ todo.text }}
</span>
<!-- Delete button - also passes todo.id -->
<button
class="btn btn-sm btn-danger ms-auto"
@click="delete_todo"
data-todo-id="{{ todo.id }}"
>
Delete
</button>
</li>
{% empty %}
<li class="list-group-item text-muted">No todos yet. Add one above!</li>
{% endfor %}
</ul>
</div>
{% endblock %}
Create your own components with their own class, template, and logic
# components/user_card.py
from django_rust_live.components.base import LiveComponent
class UserCardComponent(LiveComponent):
"""Reusable user profile card component"""
template_name = 'components/user_card.html'
def mount(self, user, show_email=True):
"""Initialize component with user data"""
self.user = user
self.show_email = show_email
self.is_expanded = False
def get_context(self):
"""Return data for template rendering"""
return {
'user': self.user,
'show_email': self.show_email,
'is_expanded': self.is_expanded,
}
def toggle_expand(self):
"""Event handler - can be called from template"""
self.is_expanded = not self.is_expanded
self.trigger_update() # Notify parent to re-render
# Use the component in a LiveView
from .components.user_card import UserCardComponent
class TeamView(LiveView):
template_name = "team.html"
def mount(self, request):
# Create multiple instances of your custom component
self.user_cards = [
UserCardComponent(user=user, show_email=True)
for user in User.objects.all()[:5]
]
Component Template: components/user_card.html
<!-- components/user_card.html -->
<div class="card mb-3" id="{{ component_id }}">
<div class="card-body">
<div class="d-flex align-items-center">
<img src="{{ user.avatar_url }}" class="rounded-circle me-3" width="50">
<div class="flex-grow-1">
<h5 class="mb-0">{{ user.get_full_name }}</h5>
{% if show_email %}
<small class="text-muted">{{ user.email }}</small>
{% endif %}
</div>
<button class="btn btn-sm btn-outline-primary" @click="toggle_expand">
{% if is_expanded %}Less{% else %}More{% endif %}
</button>
</div>
<!-- Expanded content -->
{% if is_expanded %}
<div class="mt-3 pt-3 border-top">
<p><strong>Role:</strong> {{ user.role }}</p>
<p><strong>Joined:</strong> {{ user.date_joined|date:"M d, Y" }}</p>
</div>
{% endif %}
</div>
</div>
Using in Parent Template: team.html
<!-- team.html -->
{% extends "base.html" %}
{% block content %}
<div data-liveview-root>
<h2>Team Members</h2>
<!-- Render each user card component -->
{% for card in user_cards %}
{{ card.render }}
{% endfor %}
</div>
{% endblock %}
Wire up LiveViews like regular Django class-based views
# urls.py
from django.urls import path
from .views import CounterView, ContactFormView, TodoListView
urlpatterns = [
# LiveViews work like any Django CBV
path('counter/', CounterView.as_view(), name='counter'),
path('contact/', ContactFormView.as_view(), name='contact'),
path('todos/', TodoListView.as_view(), name='todos'),
]
Components automatically sync with server state using Rust-powered VDOM diffing.
Render components with Bootstrap 5, Tailwind CSS, or plain HTML.
All interactivity handled server-side with WebSocket updates.
Python type hints ensure correct component usage.