# Toast Short notices that stack at an edge of the screen, pause on hover and close on their own or with a swipe. ```ehtml Example import { Toaster, Toast, toast } from "@elements/ui/toast"; import { Button } from "@elements/ui/button"; ``` ## Parts | Part | What it is | |---|---| | `Toaster` | The region toasts render in: a top-layer `
` with one stack per position. Mount it once, in the app shell. | | `Toast` | A declarative toast: shown while open is true; writes open = false back when it closes itself (timer, swipe, close, Escape, action). A literal open is uncontrolled: it shows when it renders. | | `toast()` | The imperative API, imported beside Toaster: toast(title, options), toast.success, info, warning, error, loading, message, promise, custom, update, dismiss, getToasts (getActiveToasts) and getHistory. Same id updates a toast in place. | | `.toast` | One toast: .toast-close, .toast-icon (loader and icon in one cell), .toast-arrow (anchored, with positioner.arrow), .toast-content (.toast-title, .toast-description), .toast-cancel, .toast-action. A toast.custom() toast holds .toast-custom instead. | ## Attributes ### Toaster | Attribute | Type | Default | Description | |---|---|---|---| | `position` | `"top-left" \| "top-center" \| "top-right" \| "bottom-left" \| "bottom-center" \| "bottom-right"` | `"bottom-right"` | Where the stack sits. A toast may name its own position; it then renders in a second stack. | | `expand` | `boolean` | `false` | Keep the stack fanned out. Otherwise it fans out on hover, focus or the hotkey. | | `visibleToasts` | `number` | `3` | Toasts past this many are hidden and inert until those in front close. | | `duration` | `number` | `4000` | Default time on screen in ms. A toast's own duration wins; Infinity stays until dismissed. | | `gap` | `number` | `-1` | px between fanned-out toasts. -1 reads the theme (--space-3-5). | | `offset` | `string \| number \| { top, right, bottom, left }` | `""` | Distance from the viewport edges. "" reads the theme (--space-6). | | `mobileOffset` | `string \| number \| { top, right, bottom, left }` | `""` | The same under 600px. "" reads the theme (--space-4). | | `closeButton` | `boolean` | `false` | A close button on every toast. | | `richColors` | `boolean` | `false` | Success, info, warning and error toasts take their status colors. | | `invert` | `boolean` | `false` | Inverse colors: a dark toast on a light page. | | `theme` | `"" \| "light" \| "dark" \| "system"` | `""` | Light or dark toasts whatever the page's mode; system follows the OS. "" follows the page. | | `hotkey` | `string[]` | `["altKey", "KeyT"]` | Focuses the region and fans out the stack. Each entry is a modifier property or an event.code or key, such as ["F8"]. | | `dir` | `"ltr" \| "rtl" \| "auto"` | `"auto"` | Text direction of the stacks; auto reads the document. | | `swipeDirections` | `SwipeDirection[]` | `[]` | Directions a swipe may dismiss toward. [] derives them from the position (bottom-right: bottom and right). | | `swipeThreshold` | `number` | `45` | px a swipe must travel to dismiss on release. A quick flick also dismisses. | | `id` | `string` | `""` | Names this Toaster; only toasts with the same toasterId render in it. | | `label` | `string` | `"Notifications"` | The region's name; the hotkey is appended. | | `ariaLabel` | `string` | `""` | Replaces the whole region name. | | `closeButtonLabel` | `string` | `"Close toast"` | The close button's accessible name. | | `icons` | `{ success?, info?, warning?, error?, loading?, close?: IconName \| false }` | `{}` | Replace or hide the icon per type. | | `toastOptions` | `{ class?, classes?, style?, duration?, closeButton?, unstyled?, closeButtonLabel? }` | `{}` | Defaults for every toast in this Toaster. | | `class` | `string` | `""` | Extra classes on the region. | | `style` | `string` | `""` | Inline style on the region. | ### Toast | Attribute | Type | Default | Description | |---|---|---|---| | `open` | `boolean` (two-way) | `false` | Shows the toast while true. Bind it; the toast writes false back when it closes itself. | | `title, description, type` | `string \| ((t: ToastItem) => string), string \| ((t: ToastItem) => string), ToastType` | `"", "", "default"` | Its content and kind. | | `duration, dismissible, closeButton, richColors, invert, important, icon, action, cancel, position, toasterId, swipeDirections, testId, class` | `as the toast() options` | `as the toast() options` | The same options as toast(). | | `onOpenChange` | `(open: boolean) => void` | `() => {}` | Called when the toast closes itself; not when the caller sets open. | | `onEscapeKeyDown, onPause, onResume, onSwipeStart, onSwipeMove, onSwipeEnd, onSwipeCancel` | `functions` | `() => {}` | As the toast() options. | ### toast() options | Attribute | Type | Default | Description | |---|---|---|---| | `description` | `string \| ((t: ToastItem) => string)` | `""` | Second line under the title. A function is given the toast and re-renders when what it reads changes. | | `data` | `unknown` | `undefined` | Your own values, for a function title or description (t.data) and toast.custom(). | | `anchor` | `Element \| null` | `null` | Shows the toast next to this element instead of in the stack. | | `positioner` | `{ side?, align?, sideOffset?, alignOffset?, arrow?, arrowPadding?, collisionAvoidance?, collisionBoundary?, collisionPadding?, sticky?, positionMethod?, disableAnchorTracking?, class?, style? }` | `{}` | How an anchored toast sits against its anchor; side defaults to top. arrow draws one pointing at the anchor. | | `swipeDirections` | `SwipeDirection[]` | `the Toaster's` | The directions that dismiss this toast, over the Toaster's. | | `id` | `string \| number` | `generated` | Reuse an id to update a toast in place; its timer restarts. | | `action` | `{ label, onClick?, altText?, class?, style? } \| Node` | `none` | A primary button. It closes the toast unless onClick calls e.preventDefault(). altText is read to screen readers. An element of your own renders in its place and keeps its own handlers. | | `cancel` | `{ label, onClick?, class?, style? } \| Node` | `none` | A secondary button; runs onClick and closes. An element of your own renders in its place. | | `duration` | `number` | `the Toaster's` | ms on screen; Infinity stays. | | `dismissible` | `boolean` | `true` | false: no swipe, no close, no Escape. | | `icon` | `IconName \| false` | `the type's` | Replace the type icon, or hide it. | | `important` | `boolean` | `false` | Announced assertively, interrupting the screen reader. | | `closeButton, richColors, invert, position, toasterId` | `as on Toaster` | `the Toaster's` | Override the Toaster's for this toast. | | `testId, class, classes, style, unstyled` | `string, string, ToastClasses, string, boolean` | `"", "", {}, "", false` | data-testid, extra classes (per part with classes), inline style, and no chrome. | | `onDismiss, onAutoClose, onPause, onResume, onEscapeKeyDown, onSwipeStart, onSwipeMove, onSwipeEnd, onSwipeCancel` | `functions` | `none` | Closed by the user or toast.dismiss; closed by its timer; timer paused and resumed; Escape (preventable); swipe phases. | | `onClose, onRemove` | `(t: ToastItem) => void` | `none` | The toast starts to close, for any reason; its exit finished and it left the page. | ## Keyboard | Keys | Action | |---|---| | `Alt + T` | The hotkey: focuses the region and fans out the stack, from anywhere on the page. Pressed again from inside, returns focus. | | `Tab / Shift + Tab` | Moves through the toasts, newest first, and their buttons. Tab past the last returns focus to where the hotkey was pressed. | | `Space / Enter` | On the action, cancel or close button: runs it and closes the toast. | | `Escape` | On a toast: closes it and moves focus to the next. On the region: folds the stack and returns focus. | ## Data attributes | Attribute | Values | On | Description | |---|---|---|---| | `data-y-position, data-x-position` | `"top" \| "bottom"; "left" \| "center" \| "right"` | .toaster-list, .toast | | | `data-expanded` | `"true" \| "false"` | .toaster-list, .toast | Fanned out. | | `data-type` | `"default" \| "success" \| "info" \| "warning" \| "error" \| "loading"` | .toast | | | `data-mounted` | `"true" \| "false"` | .toast | false for the first frame; the enter transition runs off it. | | `data-removed` | `"true" \| "false"` | .toast | true during the exit. | | `data-state` | `"open" \| "closed"` | .toast | closed during the exit. | | `data-front` | `"true" \| "false"` | .toast | The newest toast. | | `data-visible` | `"true" \| "false"` | .toast | false past visibleToasts. | | `data-index` | 0..n | .toast | | | `data-swiping, data-swiped, data-swipe-out` | `"true" \| "false"` | .toast | | | `data-swipe` | `"start" \| "move" \| "cancel" \| "end"` | .toast | The phase of a swipe. | | `data-swipe-direction` | `"left" \| "right" \| "up" \| "down"` | .toast | Where a swiped toast leaves. | | `data-rich-colors, data-invert, data-dismissible, data-promise, data-styled` | `"true" \| "false"` | .toast | | | `--offset, --index, --z-index, --initial-height, --swipe-amount-x, --swipe-amount-y` | custom properties | .toast | Layout and swipe offsets for custom styles. | | `--toast-index, --toast-height, --toast-offset-y, --toast-swipe-movement-x, --toast-swipe-movement-y` | custom properties | .toast | The same numbers under these names too; --toast-frontmost-height on the list. | | `data-limited, data-starting-style, data-ending-style` | `"true" \| "false"; present` | .toast | Past visibleToasts; before the enter; during the exit. | | `data-update-key, data-updated` | count; present | .toast | Updates by id; set again on each, so a CSS animation on it replays. | | `data-anchored, data-side, data-align, data-anchor-hidden` | present; side; align | .toaster-list | An anchored toast's list, as placed against its anchor. | | `data-behind` | `"true" \| "false"` | .toast-content | Behind the front toast. | | `data-swipe-ignore` | present | your element | A press on it never starts a swipe; nor does one on a button, link or field. | ## Accessibility - The region is a `
` named "Notifications alt+T": the hotkey is in its name so it can be found. - Each toast is announced when it appears and when its title or type changes (a promise settling): title, description and the action's altText. important toasts use the assertive live region; others the polite one. - Each toast is role="status" with aria-live off: named by its title (aria-labelledby) and described by its description (aria-describedby), so a focused toast is read by name; its announcement comes from the live region. - Toasts never take focus on their own. The hotkey moves focus into the region; Tab past the last toast, or Escape on the region, returns it. - Timers pause while the pointer is over the stack, while keyboard focus is in it, while a toast is pressed (a press released off the stack lets it go), while the window is in the background and while the tab is hidden. - Hidden toasts beyond visibleToasts are inert. The close button has an accessible name; icons are decorative. On a non-dismissible toast the close and cancel buttons are aria-disabled. - With prefers-reduced-motion, toasts appear, restack and swipe out with no motion. - The region is a manual popover in the top layer, re-shown when a toast arrives, so toasts draw above dialogs and popovers opened before them. While a native modal dialog is open the region moves into the dialog's panel (still in the top layer), so its toasts are announced from a live region inside the dialog, and the hotkey, Tab, presses, hover and swipes reach them while the dialog stays open. Escape on a toast closes the toast, not the dialog. ## See also - [Button](button): A button or a link that looks like one, in six variants and four sizes.