cashmere

cashmere

How to display messages with actix web and htmx

Preface

This guide demonstrates how to display dynamic messages (e.g., notifications or alerts) in a web application using Actix Web for the backend and HTMX for seamless frontend interactions. By combining these technologies with Askama for templating, you can render server-side notifications that are swapped into the DOM without full page reloads. The example includes configuration for HTMX response handling, a reusable notification template, and Rust handlers to trigger messages based on server-side logic.

Example

HTML

base.html

<!doctype html>
<html lang="en" data-theme="autumn">
  <head>
    <meta
      name="htmx-config"
      content='{
        "responseHandling":[
            {"code":"204", "swap": false},
            {"code":"[23]..", "swap": true},
            {"code":"[45]..", "swap": true, "target": "#notifications"},
            {"code":"...", "swap": true}
        ]
    }'
    />
    <meta name="title" content="" />
    <meta name="description" content="" />
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>{{ page_title }}</title>
    <link rel="stylesheet" type="text/css" href="/static/output.css" />
    <script src="/static/htmx.min.js"></script>
    <script defer src="/static/alpine.min.js"></script>
    <script type="module" src="https://unpkg.com/cally"></script>
    {% block head %}{% endblock %}
  </head>
  <body class="font-primary">
    {% include "./components/navbar.html" %} {% block content %}{% endblock %} {% include "./components/footer.html" %}
  </body>
</html>

notifications.html

<div x-data="{ show: true }" x-show="show" x-init="setTimeout(() => show = false, 5000)"
     class="toast toast-top toast-end">
  <div class="alert alert-error">
    <span class="font-bold text-lg">{{message|safe}}</span>
  </div>
</div>

Rust

notifications.rs

use actix_web::{HttpResponse, Result};
use askama::Template;

#[derive(Template)]
#[template(path = "notification.html")]
pub struct NotificationTemplate {
    pub message: String,
}

pub async fn message_err(message: &str) -> Result<HttpResponse> {
    let notification = NotificationTemplate {
        message: message.into(),
    };

    return Ok(HttpResponse::InternalServerError()
        .content_type("text/html")
        .body(notification.render().unwrap()));
}

example.rs

#[post("/example-handler")]
pub async fn example_actix_web_fn() -> Result<HttpResponse> {
    return message_err("this is my custom message").await;
}

References

</> htmx ~ Documentation - Requests & Responses