Skip to content

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)