---
title: Toast
description: Toasts surface brief, non-blocking feedback after an action, such as save confirmations, errors, or background sync status.
category: Feedback
---
import { meta as ToastMeta, Default, AlwaysExpanded, Positions } from '@/content/stories/toast';
import Canvas from '@/components/component-docs/canvas';
import Demo from '@/components/component-docs/demo';
export const config = {
dependencies: {
components: [Canvas, Demo],
scripts: [
'../../components/component-docs/demo.script.tsx',
'../../components/component-docs/canvas.script.tsx',
'../../components/component-docs/controls.script.tsx',
],
},
};
# Toast
Toasts surface brief, non-blocking feedback after an action, such as save confirmations, errors, or background sync status.
## Try it
## Usage
Mount `RuiToaster` once at the app root, then call `toast()` imperatively to show messages. Each call returns a toast id you can pass to `toast.dismiss()`.
```tsx
import { RuiToaster, toast } from '@ecopages/radiant-ui/toast';
import { RuiButton } from '@ecopages/radiant-ui/button';
toast.success('Changes saved')}>
Save
```
The imperative `toast()` helper is Sonner-shaped: `toast()`, `toast.message()`, `toast.success()`, `toast.error()`, `toast.info()`, `toast.warning()`, `toast.loading()`, `toast.promise()`, `toast.dismiss(id?)`, and `toast.clear()`.
## Match variant to message
Use `success` for confirmations, `error` for failures, `warning` for caution, and `info` for neutral updates. `loading` shows a spinner and never auto-dismisses.
```tsx
toast.success('Changes saved');
toast.error('Unable to reach the server', { description: 'Try again in a moment.' });
toast.warning('Disk space is running low');
toast.info('Your session will expire soon');
```
## Theming
Toast variants reuse the **semantic status roles** from the active theme (the same `info` / `success` / `warning` / `error` families as alerts) via `.rui-toast--*` on the composed surface:
| `variant` | Semantic role | Typical utilities on `.rui-toast--*` |
| --- | --- | --- |
| `info` | `info` | `border-info/40`, `text-info` |
| `success` | `success` | `border-success/40`, `text-success` |
| `warning` | `warning` | `border-warning/40`, `text-warning` |
| `error` | `error` (destructive) | `border-error/40`, `text-error` |
| `loading` | neutral surface | `border-border`, `text-on-surface` |
The surface stays `bg-surface text-on-surface` with a per-variant border and text accent, so toasts read as floating chrome rather than filled status blocks. Remap status roles at the theme layer (`tokens/presets/colors/*.css`) for global mood.
Toaster geometry uses `--rui-toaster-*` on `rui-toaster`. `gap` and `offset` attributes write `--rui-toaster-gap` and `--rui-toaster-offset` and win over CSS.
| Knob | Default | Notes |
| --- | --- | --- |
| `--rui-toaster-width` | `356px` | CSS-only; not written by JS |
| `--rui-toaster-gap` | `14px` | `gap` attribute wins |
| `--rui-toaster-offset` | `24px` | `offset` attribute wins |
| `--rui-toaster-inset-x` / `--rui-toaster-inset-bottom` | `16px` | used below 600px |
```css
rui-toaster {
--rui-toaster-width: 28rem;
}
```
## Duration and dismissal
Set `duration` per toast for urgent vs routine messages. Toasts pause their countdown while hovered, while a pointer is interacting, or while the tab is hidden, and resume from the remaining time.
```tsx
toast('Autosaved', { duration: 2000 });
toast.error('Sync failed', { duration: 10_000, closeButton: true });
```
Enable `closeButton` when users need time to read, or `dismissible` to allow swipe-to-dismiss. `toast.promise()` drives a single toast through loading → success/error:
```tsx
toast.promise(save(), {
loading: 'Saving…',
success: 'Saved',
error: 'Save failed',
});
```
## Stacking
Toasts stack at the configured corner. By default the stack collapses behind the front toast (peek) and expands on hover; set `expand` to always show full gaps.
```tsx
```
`visibleToasts` caps how many stay mounted at once; older toasts wait in the queue.
## Position
Place the stack at any corner or edge center.
```tsx
```
## Accessibility
- Toasts use `role="status"` for polite announcements that do not interrupt current tasks; the toaster wraps the stack in an `aria-live="polite"` region.
- Error toasts use `role="alert"` semantics for immediate attention.
- Do not rely on toasts alone for critical errors; pair with inline field errors when appropriate.
- The stack region is focusable (`tabindex="-1"`) so keyboard users can inspect messages; close controls are labeled buttons.
## Why a custom element?
`` owns dismiss lifetime bookkeeping (pause on hover / hidden tab, swipe-to-dismiss, and exit animation) which requires DOM state. `` owns the stack layout (peek/expand math, per-position filtering). The `RuiToast` / `RuiToaster` JSX helpers are thin passthroughs; the elements render their own composed light-DOM surface.
## API
### Imperative API
The `toast()` callable and its variants accept `(title, options?)` where `options` is `ToastOptions`:
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `id` | `string \| number` | auto | Dismiss a specific toast by id. |
| `description` | `string` | | Supporting detail under the title. |
| `duration` | `number` | `4000` | Lifetime in ms; `Infinity` keeps it until dismissed. |
| `action` | `{ label, onClick }` | | Render an action button. |
| `dismissible` | `boolean` | `true` | Allow close button / swipe-to-dismiss. |
| `closeButton` | `boolean` | toaster default | Show the corner close control. |
| `position` | `ToastPosition` | toaster default | Per-toast placement override. |
### `` attributes
| Attribute | Type | Default | Description |
| --- | --- | --- | --- |
| `position` | `top/bottom-start/center/end` | `bottom-end` | Corner / edge placement. |
| `duration` | `number` | `4000` | Default lifetime in ms. |
| `visible-toasts` | `number` | `3` | Max toasts mounted at once; older wait in queue. |
| `close-button` | `boolean` | `false` | Show a close button on every toast. |
| `expand` | `boolean` | `false` | Always render the stack expanded. |
| `gap` | `number` | `14` | Gap between expanded toasts in px. |
| `offset` | `number` | `24` | Viewport inset in px. |
| `container` | `string` | `''` | CSS selector for a positioning root (docs canvas). |
### Derived tree
`` and `` are **Derived Tree** hosts: the toaster `render()`s `[data-ref="list"]` and `rui-toast` children; each toast `render()`s `[data-ref="toast"]`, `[data-toast-close]`, and `[data-toast-action]`. Use the imperative `toast()` API — do not author these targets by hand.
The toaster queries `[data-ref="list"]` and `[data-ref="toast"]` for layout math.
### `` attributes
Rendered by the toaster; listed for completeness. Documented via `@attr` on `RuiToastElement`.
| Attribute | Type | Default | Description |
| --- | --- | --- | --- |
| `toast-id` | `string` | `''` | Toast id for deadline bookkeeping. |
| `title` | `string` | `''` | Heading text. |
| `description` | `string` | `''` | Supporting detail. |
| `variant` | `default` · `info` · `success` · `warning` · `error` · `loading` | `default` | Status tone. |
| `duration` | `number` | `4000` | Lifetime before auto-dismiss. |
| `dismissible` | `boolean` | `true` | Allow close / swipe. |
| `close-button` | `boolean` | `false` | Corner close control. |
| `action-label` | `string` | `''` | Action button text. |
| `position` | `ToastPosition` | `bottom-end` | Placement; mirrors the toaster. |
| `marked-delete` | `boolean` | `false` | Marks for animated exit. |
### Events
| Event | Detail | Description |
| --- | --- | --- |
| `rui-toast-show` | `ToastShowDetail` | Document-level; the toaster listens and creates a toast. |
| `rui-toast-dismiss` | `{ id? }` | Document-level; the toaster dismisses the matching toast. |
| `rui-toast-mounted` | | Bubbles after a toast mounts and paints; the toaster resyncs stack layout. |
Use `showToast()` / `dismissToast()` to dispatch the document events, or the simpler `toast()` API.
### CSS classes
Public BEM classes on the composed light-DOM surface (documented via `@cssclass` on the elements):
| Class | Description |
| --- | --- |
| `.rui-toaster-region` | Announcement region wrapper (`display: contents`). |
| `.rui-toaster` | The `` stack list. |
| `.rui-toast` | Toast surface (`role="status"`). |
| `.rui-toast--info` | Info tone. |
| `.rui-toast--success` | Success tone. |
| `.rui-toast--warning` | Warning tone. |
| `.rui-toast--error` | Error tone. |
| `.rui-toast--loading` | Loading tone. |
| `.rui-toast__icon` | Status icon wrapper. |
| `.rui-toast__loader` | Spinner for `loading` toasts. |
| `.rui-toast__content` | Title + description column. |
| `.rui-toast__title` | Heading. |
| `.rui-toast__description` | Supporting detail. |
| `.rui-toast__action` | Optional action button. |
| `.rui-toast__close` | Corner close control. |
### Theme roles (per `variant`)
| Variant | CSS variables consumed |
| --- | --- |
| `info` | `--info` |
| `success` | `--success` |
| `warning` | `--warning` |
| `error` | `--error` |
| `loading` | `--border`, `--on-surface` |
`error` is the destructive status role (same family as destructive buttons). Surface and text roles are `--surface` / `--on-surface` for all variants.