SwapResponse - Multi-Target Updates

Update multiple parts of your page with a single HTTP response.

Overview

SwapResponse enables you to update multiple UI elements, show toasts, trigger client events, and coordinate complex UIs with a single, fluent API call.

One HTTP request. Multiple UI updates. Zero JavaScript.


Basic Usage

[HttpPost]
public IActionResult UpdateProduct(Product product)
{
    _productService.Update(product);
    
    return SwapResponse()
        .WithView("_ProductCard", product)
        .WithSuccessToast("Product updated!")
        .Build();
}

Multi-Target Updates

Update several page elements at once:

[HttpPost]
public IActionResult AddToCart(int productId)
{
    var cart = _cartService.AddProduct(productId);
    var product = _productService.GetById(productId);
    
    return SwapResponse()
        .WithView("_ProductCard", product)            // Update main content
        .AlsoUpdate("cart-count", "_CartCount", cart.ItemCount)  // Update header badge
        .AlsoUpdate("cart-preview", "_CartPreview", cart)         // Update cart dropdown
        .WithSuccessToast("Added to cart!")
        .Build();
}

View structure:

<!-- Main content area (default target) -->
<div id="product-card">
    @await Html.PartialAsync("_ProductCard", Model)
</div>

<!-- Header cart count -->
<span id="cart-count">@ViewBag.CartCount</span>

<!-- Cart dropdown -->
<div id="cart-preview">
    @await Html.PartialAsync("_CartPreview", CartModel)
</div>

Toast Notifications

Show feedback without extra HTML:

// Success toast
return SwapResponse()
    .WithView("_Form", model)
    .WithSuccessToast("Saved successfully!")
    .Build();

// Error toast
return SwapResponse()
    .WithView("_Form", model)
    .WithErrorToast("Something went wrong")
    .Build();

// Info/Warning toasts
.WithInfoToast("Processing...")
.WithWarningToast("Almost full")

Out-of-Band (OOB) Swaps

Update elements outside the main target using HTMX's OOB feature:

return SwapResponse()
    .WithView("_ProductList", products)
    .WithOobSwap("notification-badge", "_NotificationBadge", notificationCount)
    .Build();

The OOB element will be updated anywhere on the page, even if it's not in the main target area.


Triggering Client Events

Coordinate with JavaScript when needed:

return SwapResponse()
    .WithView("_Modal", model)
    .TriggerClientEvent("modalOpened", new { modalId = "product-modal" })
    .Build();

Listen on the client:

document.body.addEventListener('modalOpened', function(event) {
    console.log('Modal opened:', event.detail.modalId);
});

HTTP Headers

Control HTMX behavior via response headers:

return SwapResponse()
    .WithView("_Product", product)
    .PushUrl($"/products/{product.Id}")  // Update browser URL
    .Build();

// Or redirect
return SwapResponse()
    .WithView("_Success", model)
    .Redirect("/products")
    .Build();

Chaining Methods

All methods are chainable for readability:

return SwapResponse()
    .WithView("_OrderConfirmation", order)
    .AlsoUpdate("cart-count", "_CartCount", 0)
    .AlsoUpdate("user-credits", "_Credits", user.Credits)
    .WithSuccessToast($"Order #{order.Id} placed!")
    .TriggerClientEvent("orderPlaced", order)
    .PushUrl($"/orders/{order.Id}")
    .Build();

Error Handling

Handle validation errors gracefully:

[HttpPost]
public IActionResult Create([FromForm] ProductModel model)
{
    if (!ModelState.IsValid)
    {
        return SwapResponse()
            .WithView("_ProductForm", model)
            .WithErrorToast("Please fix the errors")
            .Build();
    }
    
    // ... save product
}

Performance Tips

  • Batch updates: Use SwapResponse to send multiple updates in one request instead of multiple AJAX calls
  • Keep partials small: Each AlsoUpdate() renders a partial—keep them focused
  • Use Source Generators: Type-safe element IDs prevent runtime errors