Toast
A message that arrives after the page did — and the only component here with no registry entry at all.
src/components/rahti_ui/toast.rs
The toast
A title, a description and something to do about it.
shadcn's own demo. `toast.add({…})` is a function call, not markup — which is why this component is the one place in the library with an imperative API. There is no Rust for a browser event handler, so the Toaster's script publishes `window.toast` and a PulsePoint expression calls it the same way it already calls `twMerge`.
The `Undo` button and the close button are both real `button_variants(…)` lists — shadcn passes them as `render={<Button …/>}`, which crosses here as a class list the way `asChild` does everywhere else.
Types
Five icons, one class list.
shadcn's five types. Each one draws a different icon and nothing else — the error's is the only coloured one and the loading one the only moving one, both of which are shadcn's choices.
All five icons are server-rendered into the Toaster's `<template>` and the script un-hides one. That is what keeps this file's class strings in Rust: the script clones a shape the server wrote, and never builds markup.
Stacking
What happens when more than one arrives.
Press `Add five` and then hover the stack. Collapsed, the ones behind peek out by 12px each and shrink by 10% per step, and their content is faded right out. Hovered, they fan out to their own heights and every clock in the stack pauses — which is the behaviour that makes a toast readable at all.
Only three are drawn; the fourth and fifth are there but faded, which is the `data-limited` half of the class list. Push one away with a swipe in any of the four directions, or press Escape while one has focus.
None of that is written by the script as a style. The script keeps six custom properties and five data attributes true and the class list does the drawing — see the section below for the list.
Promise
One toast that becomes another when something finishes.
shadcn's promise demo. A loading toast goes up straight away and swaps for a success or an error when the promise settles — `success` and `error` may be strings or functions of the settled value, which is shadcn's shape.
A loading toast has no timeout of its own: whatever it is waiting for decides when it goes. The swap gives it the ordinary five seconds back.
`toast.promise` returns the promise, re-thrown on failure — so the second button has to `.catch()` or the console fills with unhandled rejections. That is deliberate: swallowing a rejection inside a toast helper would hide a real error from the page that raised it.
The machine
Eleven values, and a class list that reads all of them.
Base UI publishes every one of these, and nothing else does — so a port that copied the class strings and skipped them would ship sixteen lines of dead Tailwind. Keeping these eleven true *is* the port; the class list then does the drawing without the script touching a single style beyond the properties themselves.
The numbers, spelled out: a toast stays 5000ms, its exit is given 500ms — which is what the class list's own `transform_500ms` needs — 3 are drawn before the rest fade, and a swipe has to travel 45px before it counts as a throw rather than a wobble.
The port
What crossed, what could not, and what was added.
Sixth component in a row where the registry is not the source — and the first where there is no registry entry to be behind. What is missing is named above rather than quietly absent, which is the standard the rest of these ports hold to.
One `<Toaster />` per page, and the sensible place is the root layout. This page has its own at the bottom so the demos are self-contained; a second one anywhere would publish the global twice, and the script says so in the console rather than silently winning.