# Toast A transient confirmation, mounted once near the app root. - Group: Feedback - Import: `import { Toaster } from '@misoto22/folio'` - Page: https://ui.misoto22.com/components/toast/ - Related: alert ## When to reach for it Something succeeded and needs no response. A toast is dismissed by time, and time is not an acknowledgement. ## Anatomy - **Toaster** (required) — The single mount, bottom-right by default. It renders sonner’s list into a portal at the end of body, which is why the theming is an inline style — a stylesheet scoped to the app never reaches there. - **Token style** (required) — sonner’s --normal-bg, --normal-text, --normal-border and --border-radius pointed at --paper, --ink, --rule-2 and --radius, plus the sans face. The --success-* and --error-* pairs join them only when richColors is on, which is the only state sonner reads them in. - **Notification region** (required) — sonner’s own section, aria-live="polite" and labelled “Notifications altKey+KeyT”. Taken out of the tab order and reachable by that shortcut, and polite for every toast type — there is no assertive path. - **Toast** — One entry, pushed by toast() or one of its typed variants and removed from the DOM after sonner’s default four seconds, which this wrapper does not change. Three are visible at once; the rest queue. - **Close button** — On by default here, where sonner ships it off. Without it the only ways out are the timer and a swipe, and a keyboard has no swipe. ## Best practices ### Do - Mount exactly one Toaster. Every toast() call reaches every Toaster listening, so one in a root layout and one in a nested layout render the same message twice, in two corners. - Set duration per toast for anything longer than a short sentence. The wrapper leaves sonner’s default at four seconds — roughly ten words read aloud — and the rest of the message is removed from the page before it has been read. - Keep the message to what happened. Three toasts are visible at a time and the rest wait their turn, so a loop that toasts per item shows the last three and delivers the others after the reader has moved on. - Set data-mode on and leave theme alone. sonner hard-codes the description’s colour per theme — #3f3f3f, overridden only under its dark theme — so a page painted dark by an attribute the Toaster was not following put that grey on --paper at roughly 1.85:1, and every toast with a description lost its second half. ### Don’t - Nothing a reader must act on belongs here. Four seconds is a deadline they were never told about, and the button is in a portal at the end of body that a keyboard reaches last — an Undo in a toast is an offer most people cannot take. - Nothing a reader must read twice belongs here either — an error code, a reference, a name to type elsewhere. There is no history: once the timer expires the text is out of the DOM and unrecoverable. - Do not report a failure with toast.error and consider it reported. The region is polite for every type, so the failure queues behind whatever the screen reader was already saying and can be removed before its turn comes. - Do not pass theme="system". It reads prefers-color-scheme, not data-mode, so a reader who overrode a dark operating system with a light page gets a dark toast over it — the same defect the old default had, pointing the other way. ## Toaster Transient confirmations, mounted once near the app root. A toast is for something that succeeded and needs no response. Anything the reader must act on belongs in the page — a toast is dismissed by time, and time is not an acknowledgement. `theme` follows `data-mode`. sonner defaults to `light` and hard-codes the description's colour per theme — `#3f3f3f`, overridden only under `[data-sonner-theme=dark]` — so a Toaster that never passed `theme` put dark grey text on this system's `--paper: #0d0d0d` and every `toast(title, { description })` lost its second half. Pass `theme` yourself and that wins; sonner's own `system` is the one value not to reach for, since it reads the OS rather than the attribute the page is actually painted from. `richColors` stays off by default: sonner's rich palette is not this system's status scale, and turning it on reintroduces chroma the White Reset spends only on state. ## Example — default ```tsx import { Button, Toaster, toast } from '@misoto22/folio'