PyBlade Live Components
PyBlade Live components are self-contained, reusable UI elements that encapsulates both logic (Python class) with presentation (PyBlade templates). They allow you to build dynamic, interactive user interfaces using only Python — without writing JavaScript. These components handle user interactions, maintain state on the server, and update the UI dynamically.
PyBlade Components vs PyBlade Live Components
it's important to make the diffence between PyBlade components and PyBlade Live Components. PyBlade components are simple HTML reusable pieces of UI for your frontend while PyBlade Live components has also the capabilities of being dynamic. They can be updated without full page reloading.
Creating components
A PyBlade Live component consists of two parts:
A Python class that inherits
pyblade.live.Component. It is responsible of handling logic and state.A PyBlade template that defines the component’s UI.
To create a new component, use the pyblade make:live command:
pyblade make:live TodoListIf you prefer kebab-cased names, you can use them as well:
pyblade make:live todo-listAfter running this command, PyBlade will create two new files in your application. The first will be the component's class located at <root>/live/todo_list.py where root is the root folder of your project:
from pyblade import live
class TodoList(live.Component):
def render(self):
return self.view("live.todo-list")The second will be the component's PyBlade template located at <root>/templates/live/todo_list.html where again root is the root folder of your project:
<div>
{# ... #}
</div>Alternatively, you can create these files manually.
You may use dot-notation to create your components in sub-directories. For example, given the following folder structure :
my_project/
├── my_app/
│ ├── views.py
│ ├── models.py
│ └── templates/
├── templates/
└── manage.pyThe following command will create a TodoList component in the tasks sub-directory which will be created if it doesn't exist:
pyblade make:live Tasks.TodoListThese commands whould create two files: my_project/live/tasks/todo_list.py and my_project/templates/live/tasks/todo_list.html. Resulting in the following folder structure:
Here is a sample folder structure of my_project:
my_project/
├── my_app/
│ ├── views.py
│ ├── models.py
│ └── templates/
├── live/
│ └──tasks/
│ └── todo_list.py
├── templates/
│ └── live/
│ └──tasks/
│ └── todo_list.html
└── manage.pyNote
Generated files and subfolders are always named in snake_case while the component classes are in PascalCase.
Inline components
If your component is fairly small, you may want to create an inline component. Inline components are single-file PyBlade Live components whose view template is contained directly in the render method rather than a separate file:
from pyblade import live
class TodoList(live.Component):
def render(self):
return self.inline("""
<div>
{# Your content goes here #}
</div>
"""
)You can create inline components by adding the --inline flag to the make:live command:
pyblade make:live TodoList --inlineOmitting the render method
To reduce boilerplate in your components, you can omit the render method entirely and PyBlade Live will use its own underlying render method, which returns a template with the conventional name corresponding to your component:
from pyblade import live
class TodoList(live.Component):
...If the component above is rendered on a page, PyBlade Live will automatically determine it should be rendered using the templates/live/todo_list.html template.
Rendering components
The preferred way to include a PyBlade Live component in your PyBlade template is by using a PyBlade Live component tag. PyBlade Live component tags start with live:, followed by the kebab-cased component name without extension.
<live:todo-list />If the component class is nested deeper within the live directory, you may use the . character to indicate directory nesting. For example, if we assume a component is located at live/tasks/todo_list.py, we may render it like so:
<live:tasks.todo-list />Warning
Always use kebab-case or snake_case version of the component name. Using the PascalCase version of the component name (<live:TodoList />) is invalid and won't be recognized by PyBlade Live.
The @live directive
PyBlade also provides an alternative way to render PyBlade Live components using the @live directive:
@live("counter")@live("todo-list")While this method works, it is not as intuitive as using live component tags. The tag-based syntax is visually clearer and aligns with HTML syntax.
Add key attribute when looping
When looping through data in a PyBlade Live component's template using @for, you must add a unique key attribute to the root element rendered by the loop.
Without a key attribute present within a PyBlade loop, PyBlade Live won't be able to properly match old elements to their new positions when the loop changes. This can cause many hard to diagnose issues in your application.
For example, if you are looping through a list of tasks, you may set the key attribute to the task's ID:
<div>
@for (task in tasks)
<div key="{{ task.id }}">
{# ... #}
</div>
@endfor
</div>Pro advisory
The syntax in the 2 following code snippets may be unfamiliar to you, but don't worry as we will cover it in the Passing data to components section just after !
If you are looping through a list that is rendering PyBlade Live components you may set the key as a tag attribute when using PyBlade Live component tags:
<div>
@for (task in tasks)
<live:task-item :task="task" :key="task.id"/>
@endfor
</div>Or pass the key as a third argument when using the @live directive.
<div>
@for (task in tasks)
@live("task-item", props={"task": task}, key=task.id)
@endfor
</div>Passing data to components
PyBlade Live allows you to pass initial values to component properties directly from the template.
To pass outside data into a PyBlade Live component, you can use attributes on the live component tag. This is useful when you want to initialize a component with specific data.
For example, to pass an initial value to the title property of the TodoList component, you can use the following syntax:
<live:todo-list title="Initial Title" />If you need to pass dynamic values or variables to a component, you can write Python expressions in component attributes by prefixing the attribute with a colon:
<live:todo-list :title="initial_value" />Reminder
You may already know the difference between what we call Normal attributes and Bound attributes when you learned about PyBlade components. The concept is the same with PyBlade Live components. If not you can read this section again.
Data passed to components from templates are received through the mount() lifecycle hook as method parameters. In this case, to assign the title parameter to a property, you would write a mount() method like the following:
from pyblade import live
class TodoList(live.Component):
def mount(self, title: str):
self.title = title
def render(self)
return self.view("live.todo-list")In this example, the title property will be initialized with the value "Initial Title".
You can think of the mount() method as a class constructor, the equivalent of the __init__() method. It runs on the initial load of the component, but not on subsequent requests within a page.
We will learn more about mount() and other helpful lifecycle hooks within the Lifecycle hooks section.
You can alternatively omit the mount() method and PyBlade Live will automatically set any properties on your component with names matching the passed in values, however, this will be done if and only if you explicitely declared those typed properties in your component.
from pyblade import live
class TodoList(live.Component):
title: str
def render(self)
return self.view("live.todo-list")This is effectively the same as assigning title inside a mount() method.
These properties are not reactive by default
The title property will not update automatically if the outer :title="initial_value" changes after the initial component load. This is a common point of confusion when using PyBlade Live, especially for developers who have used JavaScript frameworks like Vue or React and assume these "parameters" behave like "reactive props" in those frameworks. But, don't worry, PyBlade Live allows you to opt-in to making your props reactive.
Including custom JavaScripts
404 : Not found
Coming soon !
Full-page components
Missing feataure
This feature is not yet available. This part of documentation is for informative purposes only.
PyBlade Live allows you to assign components directly to a route in your Django application. These are called "full-page components". You can use them to build standalone pages with logic and templates, fully encapsulated within a PyBlade Live component.
To create a full-page component, define a route in your urls.py file and use the as_view() method on the component class. For example, let's imagine you want to render the TodoList component at the dedicated route: tasks/.
You can accomplish this by adding the following line to your urls.py file:
from django.urls import path
from live import TodoList
urlpatterns = [
path('tasks/', TodoList.as_view())
]Now, when you visit the tasks/ path in your browser, the TodoList component will be rendered as a full-page component and all templates inside may be updated without the need of full page relaod. This may be interesting if you're building an SPA (Single Page Application).
Accessing route parameters
When working with full-page components, you may need to access route parameters within your PyBlade Live component.
To demonstrate, first, define a route with a parameter in your urls.py file:
from django.urls import path
from live import TodoList
urlpatterns = [
path('tasks/<int:id>', TodoList.as_view())
]Here, we've defined a route with an id parameter which represents a task's ID.
Next, update your PyBlade Live component to accept the route parameter in the mount() method:
from pyblade import live
from app.models import Task
class TaskDetail(live.Component):
def mount(self, id: int):
self.task = Task.objects.get(id)
def render(self):
return self.view("task-detail")In this example, because the parameter name id matches the route parameter <int:id>, if the /tasks/1 URL is visited, PyBlade Live will pass the value of 1 as id.