Toast
View as MarkdownAnnounce transient status from an explicit toaster. Custom element
<ui-toaster role="region" aria-label="Notifications" placement="bottom-end" stack="overlap"> <ui-toast role="status"> <div data-ui-part="content"> <h2 data-ui-part="title">Preview ready</h2> <p data-ui-part="description">The static example finished building.</p> </div> <button data-ui-part="close" type="button" aria-label="Dismiss notification"> <svg aria-hidden="true" focusable="false" viewBox="0 0 16 16"> <path d="m4.5 4.5 7 7m0-7-7 7" fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="1"/> </svg> </button> </ui-toast></ui-toaster>Install
import '@timelessui/components/css/tokens.css'import '@timelessui/components/css/core/toast.css'import '@timelessui/components/css/themes/atmosphere/tokens.css'import '@timelessui/components/css/themes/atmosphere/toast.css'import '@timelessui/components/register/ui-toaster'import '@timelessui/components/register/ui-toast'A register/ import is a side effect: it defines the element as the module evaluates, so it has to run in code the browser loads. To register explicitly instead — to control the timing, or to define into another window — call the function from the matching define/ entry point, which registers nothing on its own:
import { defineToasterElement } from '@timelessui/components/define/ui-toaster'defineToasterElement()import { defineToastElement } from '@timelessui/components/define/ui-toast'defineToastElement()Anatomy
Parts are authored in your own markup and identified by the selector below, so your CSS can target the same anatomy without loading Timeless styles. Required parts must be present for the component to work. Private data-ui-internal-* hooks are written by the runtime and must never be authored.
<ui-toast>
| Part | Required | Selector | Purpose |
|---|---|---|---|
content | No | [data-ui-part~='content'] | Wrapper for the title and description. |
title | No | [data-ui-part~='title'] | Short summary line. |
description | No | [data-ui-part~='description'] | Supporting detail. |
close | No | [data-ui-part~='close'] | Dismiss button. Give it an accessible name. |
Attributes
Every value below is implemented by the stylesheets this component ships. Boolean attributes are presence-based: author the attribute with no value, or omit it.
<ui-toaster>
| Attribute | Values | Default | Description |
|---|---|---|---|
placement | top-start · top-center · top-end · bottom-start · bottom-center · bottom-end | bottom-end | Corner or edge of the viewport the toasts stack against. |
stack | overlap · list | overlap | Whether queued toasts overlap into a deck (overlap) or lay out as a full list (list). |
<ui-toast>
| Attribute | Values | Default | Description |
|---|---|---|---|
duration | any number | 5000 | Milliseconds before the toast dismisses itself. 0 keeps it open until dismissed. |
persistent | presence | absent | Present to disable auto-dismiss regardless of duration. |
Element API
Attributes above are the authoring surface. These are the DOM properties and events the registered element adds once it upgrades.
<ui-toaster>
| Property | Type | Notes |
|---|---|---|
placement | 'top-start' | 'top-center' | 'top-end' | 'bottom-start' | 'bottom-center' | 'bottom-end' | Reflects the placement attribute, documented above. |
stack | 'overlap' | 'list' | Reflects the stack attribute, documented above. |
This element dispatches no component events.
<ui-toast>
| Property | Type | Notes |
|---|---|---|
duration | string | Reflects the duration attribute, documented above. |
persistent | boolean | Reflects the persistent attribute, documented above. |
| Event | Detail | Description |
|---|---|---|
ui-dismiss | CustomEvent<ToastDismissDetail> | Dispatched when the toast is dismissed. The detail names the reason: a timeout, the close control, or the imperative API. |
Styling
Root identity: ui-toaster, ui-toast. Required stylesheets: tokens.css, core/toast.css, themes/atmosphere/tokens.css, themes/atmosphere/toast.css.
Set these custom properties to restyle the component:
| Custom property | Controls |
|---|---|
--ui-toaster-gap | Gap between toasts in list mode. |
--ui-toaster-overlap | Offset between stacked toasts in overlap mode. |
Design tokens this component reads (13)
These are global Atmosphere tokens. Change them once at the theme level rather than per component.
--ui-bg-control · --ui-bg-surface · --ui-fg · --ui-fg-muted · --ui-focus · --ui-line · --ui-radius-lg · --ui-radius-md · --ui-shadow-floating · --ui-space-1 · --ui-space-3 · --ui-space-4 · --ui-space-5
Accessibility
Keep the native elements, roles, and relationships shown in the example. Timeless adds only the state and keyboard coordination the platform does not already provide, and it never supplies your accessible names — those depend on your content.
<ui-toaster>
Follows the Alert pattern from the ARIA Authoring Practices Guide.
The toaster is the live region, and it is yours to name — author role="region" with an aria-label, or role="status" when the whole surface should announce. Timeless supplies both as a default and neither as a replacement for your own. Nothing here traps focus or steals it: a toast appears without moving the user, and is reached with Tab like anything else. Choose the role by urgency, not by appearance: role="status" on a toast is polite and waits its turn, role="alert" interrupts and should be rare.
<ui-toast>
Follows the Alert pattern from the ARIA Authoring Practices Guide.
Give the toast the role its urgency deserves — role="status" for the ordinary case, role="alert" only when it must interrupt — and give the close control an accessible name. SC 2.2.1 is the criterion to hold in mind: duration defaults to 5000ms, and the timer stops while the toast is hovered or contains focus, so nobody loses the message they are reading or the control they are reaching for. persistent, or duration="0", removes the limit outright, which is the right choice for anything the user must act on. Dismissing a toast that holds focus hands focus to a surviving toast, or back to wherever it came from, rather than dropping it on <body>.
Before JavaScript runs
The markup above is complete and usable on its own: native controls submit, labels associate, and authored ARIA is already correct. Registration adds state synchronisation, focus management, and keyboard coordination on top of it.
More examples
Open Toast in StoryLite for variants, controls, and manual testing.