Toast
Server flashes
- Profile updatedYour changes have been saved.
New message
A server-rendered row, appended like an HTMX OOB swap.
package toast
import "github.com/gsxhq/gsxui/ui"
// Server demonstrates the real-world flash-message pattern: the SERVER
// renders a toast card and the browser adopts it into the same stacking /
// timer / dismiss lifecycle as a JS-triggered toast — with zero HTMX-specific
// code. Two paths are shown:
//
// 1. A static ui.Toast rendered inline (the markup showcase). On a full page
// load a server would drain its session/request flashes into <ui.Toaster/>
// exactly like this; ui/toaster.js adopts every li[data-gsxui-toast]
// present at init — inside the toaster region, which is where a real
// flash render puts them. This standalone preview sits OUTSIDE that
// region (so it is deliberately never adopted: no timer, no stacking)
// and therefore has to opt out of the foundation's absolute stack
// positioning, which would otherwise float the preview over the page.
// The caller utility `class="static"` wins through the documented CSS
// layer order; the <ul> wrapper keeps the <li> validly parented.
// 2. A button + inline <script> that clones a pre-rendered server row (the
// ui.Toast wrapped in the <template data-server-flash-demo> below) and
// appends it into #gsxui-toaster — precisely what an HTMX out-of-band
// swap (hx-swap-oob="beforeend:#gsxui-toaster") does on the wire. The
// MutationObserver on the <ol> adopts it; no page-specific lifecycle code.
//
// This is the one-viewport-per-page model: the server is the single source of
// toast markup, ui.Toaster is mounted once, and appends flow in from anywhere.
component Server() {
<div class="flex flex-col items-start gap-4">
<ul class="list-none">
<ui.Toast
toastType="success"
title="Profile updated"
description="Your changes have been saved."
class="static"
/>
</ul>
<ui.Button variant="outline" id="sonner-server-flash-btn">Append a server flash</ui.Button>
<template data-server-flash-demo>
<ui.Toast
toastType="info"
title="New message"
description="A server-rendered row, appended like an HTMX OOB swap."
/>
</template>
<script>
document.getElementById("sonner-server-flash-btn").addEventListener("click", () => {
const tpl = document.querySelector("template[data-server-flash-demo]");
const viewport = document.getElementById("gsxui-toaster");
if (!tpl || !viewport) return;
viewport.appendChild(tpl.content.firstElementChild.cloneNode(true));
});
</script>
</div>
}