Execution Results
Execution results are objects returned from command handlers that control how components respond to user actions. They determine which components need re-rendering, what HTTP headers to set, and how the browser should behave after processing a command.
Overview
Command handlers can return different types of execution results to control the response behavior:
- Component rendering control - Mark components as dirty (needing re-render) or clean
- Navigation control - Redirect to different pages or refresh the current page
- URL management - Update the browser URL without full page reload
If a command handler returns None (or doesn't return anything), the component is automatically marked as dirty and will be re-rendered.
Available Execution Results
ComponentClean
Indicate that a component is clean and requires no re-rendering.
Use this when a command performs side effects (like logging, analytics, or background tasks) that don't change the component's visual state.
Example:
class AnalyticsComponent(LiveComponent):
...
@command
def track_click(self, call_context: CallContext[AnalyticsState], event_name: str):
"""Log user action without re-rendering the component"""
self.analytics.track(event_name, call_context.state.user_id)
return ComponentClean()
ComponentDirty
Mark a component as dirty to trigger re-rendering.
This is the default behavior when a command handler returns None.
Example:
class StockComponent(LiveComponent):
...
@command
def update_stock(self, call_context: CallContext[StockState]):
"""Update stock quantity. Component automatically re-renders"""
call_context.state.bean.stock_quantity += 1
call_context.state.bean.save()
# Returns ComponentDirty() by default
ParentDirty
Mark the parent component as dirty to trigger re-rendering.
Useful when a child component performs an action that affects the parent's data, such as deleting an item from a list or updating shared state.
Example:
class CartComponent(LiveComponent):
...
@command
def add_to_cart(self, call_context: CallContext[CartState], product_id: int):
"""Add item to cart and update parent cart counter"""
self.state.cart.append(product_id)
return ParentDirty()
RedirectPage
Redirect the browser to a different URL.
Sets the HX-Redirect header to instruct HTMX to navigate to a new page. Commonly used after successful form submissions or authentication.
Example:
class LoginComponent(LiveComponent):
...
@command
def login(self, call_context: CallContext[LoginState], username: str, password: str):
"""Authenticate user and redirect to dashboard"""
user = authenticate(username=username, password=password)
if user:
login(call_context.request, user)
return RedirectPage('/dashboard/')
call_context.state.error = 'Invalid credentials'
RefreshPage
Trigger a full page refresh in the browser.
Sets the HX-Refresh header to instruct HTMX to reload the entire page. Use sparingly, as it breaks the SPA-like experience.
Example:
class SettingsComponent(LiveComponent):
...
@command
def switch_language(self, call_context: CallContext[SettingsState], language: str):
"""Switch language and refresh page to apply changes"""
call_context.request.session['language'] = language
return RefreshPage()
ReplaceUrl
Replace the current URL in the browser without reloading the page.
Updates the browser's address bar and history without triggering a full page reload. Useful for maintaining clean URLs that reflect the current application state. See https://htmx.org/headers/hx-replace-url/.
Example:
class ProductListComponent(LiveComponent):
...
@command
def apply_search_filter(self, call_context: CallContext[ProductListState], search_term: str):
"""Apply search filter and update URL to reflect current state"""
call_context.state.search = search_term
if search_term:
return ReplaceUrl(f'/products/?search={search_term}')
else:
return ReplaceUrl('/products/')
PushUrl
Push a new URL to the browser history without reloading the page.
Updates the browser's address bar and adds a new entry to the browser history, allowing users to navigate back to previous states using the browser's back button. See https://htmx.org/headers/hx-push-url/.
Example:
class WizardComponent(LiveComponent):
...
@command
def next_step(self, call_context: CallContext[WizardState]):
"""Move to next step and update URL with history entry"""
call_context.state.current_step += 1
return PushUrl(f'/wizard/step-{call_context.state.current_step}/')
TriggerEvents
Trigger custom browser events via HTMX response headers.
Allows you to trigger JavaScript events in the browser that can be listened to with standard event listeners. Useful for coordinating between components, showing notifications, or triggering client-side actions after server processing.
See https://htmx.org/headers/hx-trigger/ for more details.
Example:
class NotificationComponent(LiveComponent):
...
@command
def save_data(self, call_context: CallContext[NotificationState]):
"""Save data and show success notification"""
call_context.state.data.save()
return TriggerEvents([
Event(
name="showNotification",
detail={"message": "Data saved successfully!", "level": "success"}
)
])
@command
def refresh_dashboard(self, call_context: CallContext[NotificationState]):
"""Trigger multiple events after data update"""
call_context.state.update_data()
return TriggerEvents([
Event(name="refreshChart", detail={"chartId": "sales-chart"}),
Event(name="updateCounter", target="#cart-counter"),
])
Using the convenience method for single events:
@command
def quick_action(self, call_context: CallContext[State]):
return TriggerEvents.single(
name="actionComplete",
detail={"timestamp": time.time()}
)
Event
Represents a browser event to be triggered via HX-Trigger headers.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
The name of the event to trigger in the browser. |
target |
str | None
|
Optional CSS selector for the element to trigger the event on. If None, the event is triggered on the element that initiated the request. |
detail |
dict[str, Any]
|
Dictionary of additional data to pass with the event. This data will be available in the event's detail property in JavaScript event listeners. |
Trigger
Specifies when events should be triggered in the HTMX lifecycle.
See https://htmx.org/headers/hx-trigger/
More Usage Examples
Basic Component Control
When you need explicit control over component rendering:
from livecomponents import LiveComponent, command, CallContext
from livecomponents.manager.execution_results import ComponentDirty, ComponentClean
class DataComponent(LiveComponent):
@command
def update_data(self, call_context: CallContext[DataState]):
"""Update component state and trigger re-render"""
call_context.state.data = "new value"
# Component will be re-rendered (default behavior)
return ComponentDirty()
@command
def log_action(self, call_context: CallContext[DataState]):
"""Log user action without triggering component re-render"""
self.analytics.track("button_clicked", call_context.state.user_id)
return ComponentClean()
Cross-Component Updates
When child components need to update their parents or siblings:
class ProductRowComponent(LiveComponent):
@command
def update_sibling(self, call_context: CallContext[ProductRowState]):
"""Update product data and refresh related sidebar component"""
self.update_product_stats()
return ComponentDirty("product-sidebar")
@command
def delete_product(self, call_context: CallContext[ProductRowState]):
"""Delete product and refresh parent product list"""
call_context.state.product.delete()
return ParentDirty()
Multiple Results
Command handlers can return a list of execution results to perform multiple actions:
class OrderComponent(LiveComponent):
@command
def complete_order(self, call_context: CallContext[OrderState]):
"""Complete order with multiple UI updates"""
order = call_context.state.order
order.status = "completed"
order.save()
return [
ComponentDirty(),
ComponentDirty("cart-counter"),
ReplaceUrl(f"/orders/{order.id}/confirmation/")
]
URL Management: PushUrl vs ReplaceUrl
Understanding when to use PushUrl versus ReplaceUrl:
class NavigationComponent(LiveComponent):
@command
def navigate_with_history(self, call_context: CallContext[NavState], page: str):
"""Navigate to a new page, adding to browser history.
Users can use the browser's back button to return to previous pages.
Use this for navigation between distinct pages or steps.
"""
call_context.state.current_page = page
return [ComponentDirty(), PushUrl(f'/app/{page}/')]
@command
def update_filters(self, call_context: CallContext[NavState], filter_value: str):
"""Update URL to reflect current filters without adding to history.
Prevents cluttering browser history with every filter change.
Use this for transient state like search queries or filters.
"""
call_context.state.filter = filter_value
return [ComponentDirty(), ReplaceUrl(f'/app/?filter={filter_value}')]
Note that most of the time you need to re-render the component when you are updating the URL, so ComponentDirty() is included in the list of execution results.
Custom Browser Events: TriggerEvents
Trigger custom JavaScript events that can be handled by standard event listeners. Useful for notifications, analytics, or coordinating between components and third-party JavaScript libraries:
class NotificationComponent(LiveComponent):
@command
def save_data(self, call_context: CallContext[NotificationState]):
"""Save data and show a notification to the user."""
call_context.state.save()
# Trigger a custom event with data
return TriggerEvents.single(
name="showNotification",
detail={
"message": "Data saved successfully!",
"level": "success"
}
)
@command
def complex_operation(self, call_context: CallContext[NotificationState]):
"""Perform operation and trigger multiple events."""
result = call_context.state.perform_operation()
# Trigger multiple events at once
return TriggerEvents([
Event(name="operationComplete", detail={"result": result}),
Event(name="refreshChart", target="#sales-chart"),
Event(name="trackAnalytics", detail={"action": "operation"}),
])
Listening to events in JavaScript:
// Listen for the custom event
document.body.addEventListener("showNotification", function(evt) {
const { message, level } = evt.detail;
// Show notification using your preferred library
showToast(message, level);
});
document.body.addEventListener("refreshChart", function(evt) {
// Refresh the chart component
refreshChartData();
});
Controlling event timing:
You can control when events fire relative to the HTMX request lifecycle:
# Fire immediately when response is received (default)
TriggerEvents.single("immediate", trigger=Trigger.AFTER_REQUEST)
# Fire after HTMX settles the DOM
TriggerEvents.single("afterSettle", trigger=Trigger.AFTER_SETTLE)
# Fire after HTMX swaps content into the DOM
TriggerEvents.single("afterSwap", trigger=Trigger.AFTER_SWAP)