Component Kitchen Sink

Explore all Django Rust Live components with live, interactive examples. All components support Bootstrap 5, Tailwind CSS, and plain HTML rendering.

Alerts & Notifications

Alert Components

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 }}

Buttons

Button Variants & Sizes

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 }}

Badges & Labels

Badge Variants
Primary Active 99+ Python

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 }}

Dropdowns

Dropdown Menus

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 }}

Cards

Basic Card

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 Dialogs

Modal Example

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 }}

Progress Indicators

Progress Bars

Simple Progress

45%

Striped & Animated

65%

Custom Label

Processing...

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 }}

Loading Spinners

Spinner Variants
Loading...
Loading...
Loading...

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 }}

Tabs & Navigation

Tabbed Interface

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 }}

Data Tables

Sortable Data Table

Click column headers to sort

IDNameEmailRoleStatus
1Alice Johnsonalice@example.comAdminactive
2Bob Smithbob@example.comUseractive
3Charlie Browncharlie@example.comUserinactive
4Diana Princediana@example.comModeratoractive
5Eve Wilsoneve@example.comUseractive

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 }}

Pagination

Basic Pagination
Large Pagination with Info
Showing 1-25 of 250 items

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 }}

Component Composition

Combining Multiple Components
User Dashboard
Active

This demonstrates how components can be composed together in complex UIs.

45%

Usage Examples

Note: Each page/route has one LiveView class that manages the entire page's state and interactivity. Within that LiveView, you can use multiple components, manage multiple state variables, and handle many different events. Think: One LiveView per page, many components per LiveView.
1. Basic Counter - Complete Example

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 %}
2. Real-time Form Validation

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 %}
3. Interactive Todo List - Event Parameters & Lists

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 %}
4. Custom Reusable Components

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 %}
5. URL Configuration & Setup

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'),
]

Framework Features

Reactive State Management

Components automatically sync with server state using Rust-powered VDOM diffing.

Multi-Framework Support

Render components with Bootstrap 5, Tailwind CSS, or plain HTML.

Zero JavaScript Required

All interactivity handled server-side with WebSocket updates.

Type-Safe Components

Python type hints ensure correct component usage.