Place one tp-toast per queue, usually once in the app shell, and call add() on it with a title and description. It renders the notifications in a labeled landmark: creating one never steals focus, F6 reaches the region, and hover, focus or a blurred window pause the timer. Swipe or the Close button dismisses.
Tab traverses active notification roots and related controls; leaving the region returns to the previous task when entered through the shortcut.
Types
type picks a status icon: success, info, warning or error. loading shows a Spinner and stays until updated.
Types
Default density
Compact density
Restart from the initial state
Show the copyable source
SuccessInfoWarningError
SuccessInfoWarningError
<div style="display:flex;flex-wrap:wrap;gap:var(--tp-space-2);justify-content:center">
<tp-button variant="outline" data-toast-type="success">Success</tp-button>
<tp-button variant="outline" data-toast-type="info">Info</tp-button>
<tp-button variant="outline" data-toast-type="warning">Warning</tp-button>
<tp-button variant="outline" data-toast-type="error">Error</tp-button>
</div>
<tp-toast id="toast-types"></tp-toast>
<script type="module">
const toaster = document.querySelector('#toast-types');
const messages = {
success: ['Invoice sent', 'INV-2041 was emailed to billing@northwind.io.'],
info: ['New version available', 'Reload to get the latest dashboard.'],
warning: ['Storage almost full', 'You have used 92 GB of 100 GB.'],
error: ['Payment failed', 'The card ending in 4242 was declined.'],
};
for (const button of document.querySelectorAll('[data-toast-type]')) {
button.addEventListener('click', () => {
const type = button.dataset.toastType;
const [title, description] = messages[type];
toaster.add({ title, description, type });
});
}
</script>
Actions
actionProperties adds a Button to the notification. An action does not close the toast by itself; close it from the handler with the action cause, as an Undo does.
Calling close(id,'action') or configuring closeOnAction:true preserves action dismissal as a distinct cause. Application handlers run before optional action dismissal; preventing that action cancels its default dismissal.
Undo
Default density
Compact density
Restart from the initial state
Show the copyable source
Delete project
Delete project
<tp-button id="toast-undo-trigger" variant="destructive">Delete project</tp-button>
<tp-toast id="toast-undo"></tp-toast>
<script type="module">
const toaster = document.querySelector('#toast-undo');
document.querySelector('#toast-undo-trigger').addEventListener('click', () => {
const id = toaster.add({
title: 'Project deleted',
description: 'Marketing site was moved to the trash.',
actionProperties: {
label: 'Undo',
onClick() {
toaster.close(id, 'action');
toaster.add({ title: 'Project restored', type: 'success', timeout: 2500 });
},
},
});
});
</script>
Promises
manager.promise() shows a loading notification for pending work and settles it into success or error content, returning the original result.
Loading is persistent even with an explicit timeout; settlement starts the settled timeout or Provider default. Settlement after close/removal or Provider destruction cannot recreate a notification.
Saving
Default density
Compact density
Restart from the initial state
Show the copyable source
positionerProperties pins a notification to the element that caused it instead of the stack, which suits short confirmations such as a copied link. anchor takes the element; side and showArrow place it.
Anchor removal begins close with anchor-removed.
Anchored
Default density
Compact density
Restart from the initial state
Show the copyable source
A fixed identifier updates the same notification on repeated presses instead of stacking copies. Use a separate tp-toast for anchored notifications when your stacked ones follow a different position or limit.
A shared manager
createToastManager() from @tweakpad/ui creates the queue on its own, so any module can raise notifications without a reference to the element. Hand it to the viewport through toastManager, usually once in the app shell.
Connect a manager to one Provider host at a time.
The manager service object may be retained across Provider lifetimes. Disconnecting its host destroys that queue lifetime, clears its notifications, and reports provider-destroyed through close/removal callbacks. Reconnecting the same host reuses the same service with a fresh queue. Pending operations from the discarded lifetime cannot recreate notifications.
Manager
Default density
Compact density
Restart from the initial state
Show the copyable source
Sync calendarDismiss all
Sync calendarDismiss all
<div style="display:flex;flex-wrap:wrap;gap:var(--tp-space-2);justify-content:center">
<tp-button id="toast-manager-sync" variant="outline">Sync calendar</tp-button>
<tp-button id="toast-manager-clear" variant="ghost">Dismiss all</tp-button>
</div>
<tp-toast id="toast-manager" label="Calendar notifications"></tp-toast>
<script type="module">
import { createToastManager } from '@tweakpad/ui';
const notifications = createToastManager({ timeout: 4000 });
document.querySelector('#toast-manager').toastManager = notifications;
// Elsewhere in the app, only the manager is needed.
let synced = 0;
document.querySelector('#toast-manager-sync').addEventListener('click', () => {
synced += 3;
notifications.add({
title: 'Calendar synced',
description: `${synced} events imported from Google Calendar.`,
type: 'success',
});
});
document.querySelector('#toast-manager-clear').addEventListener('click', () => notifications.close());
</script>
close() without an identifier dismisses every notification in the queue.
Declarative notification
A tp-toast with open shows its own content as one notification, with title as the heading. setOpen() shows or hides it from code, and duration="persistent" keeps it until dismissed.
Host content
Default density
Compact density
Restart from the initial state
Show the copyable source
Save draftYour post will stay here until you publish it.
Save draftYour post will stay here until you publish it.
<tp-button id="toast-content-trigger" variant="outline">Save draft</tp-button>
<tp-toast id="toast-content" duration="persistent" title="Draft saved">Your post will stay here until you publish it.</tp-toast>
<script type="module">
const toaster = document.querySelector('#toast-content');
document.querySelector('#toast-content-trigger').addEventListener('click', () => toaster.setOpen(true));
</script>
Position and lifetime
position places the stack in one of six logical positions. timeout sets the default lifetime in milliseconds (0 keeps notifications until dismissed), and limit caps how many stay visible; older ones wait behind the newest.
Top center, persistent
Default density
Compact density
Restart from the initial state
Show the copyable source
Go offline
Go offline
<tp-button id="toast-position-trigger" variant="outline">Go offline</tp-button>
<tp-toast id="toast-position" position="block-start center" timeout="0" limit="1"></tp-toast>
<script type="module">
const toaster = document.querySelector('#toast-position');
document.querySelector('#toast-position-trigger').addEventListener('click', () => {
toaster.add({
title: 'You are offline',
description: 'Changes are saved locally and will sync when you reconnect.',
type: 'warning',
});
});
</script>
Use priority: 'high' in add() only for urgent messages: it announces through the assertive channel and interrupts the screen reader.
API Reference
Every element also accepts motion-policy.
Attributes
AttributePropertyTypeDefaultDescriptiontimeouttimeoutnumber5000Default lifetime of a notification in milliseconds; 0 keeps notifications until dismissed.limitlimitnumber3How many notifications stay visible at once; older ones wait behind the newest.maximum-visiblemaximumVisiblenumber—Alias of limit.durationdurationnumber | 'persistent'—Lifetime of a notification as persistent or milliseconds; an alias of timeout.prioritypriority'polite' | 'assertive''polite'How urgently assistive technology announces the declarative notification; assertive interrupts.positionpositionToastPosition'block-end inline-end'Where the stack sits, as a block and an inline position in writing direction, such as block-start center.swipe-directionsswipeDirectionsreadonly ToastSwipeDirection[]['down', 'right']The directions a swipe dismisses a notification in.labellabelstring'Notifications'Accessible name of the notifications landmark.dismissibledismissiblebooleantrueWhether notifications show a Close button.show-iconshowIconbooleantrueWhether notifications show the icon of their type.openopenbooleanfalseShows the element's own content as one notification, with title as its heading.titletitlestring''Heading of the declarative notification shown with open.
Properties
PropertyTypeDefaultDescriptiontoastManagerToastManager | undefined—A queue from createToastManager() to render, so any module can raise notifications without a reference to the element.containerHTMLElement | ShadowRoot | nullnullThe element the stack renders into, in place of the top layer.managerread-onlyToastManager—The queue in use: toastManager, else the element's own; manager.promise() follows pending work.
Events
EventTypeDescriptiontp-toast-queue-changeCustomEvent<{ toasts: readonly ToastObject<Record<string, unknown>>[]; }>After the queue changes; detail.toasts lists the notifications.
Methods
MethodReturnsDescriptionadd(options)stringRaises a notification with a title, description, type and options; returns its identifier, for close() and updates.close(identifier?, cause)voidDismisses one notification by its identifier, or every notification without one.setOpen(open)voidShows or hides the declarative notification.
Slots
SlotDescriptiondefaultThe description of the declarative notification shown with open.
CSS parts
PartDescription::part(arrow)The arrow of a notification anchored to a control, with showArrow.::part(positioner)The layer that places a notification in the stack, or against its anchor.::part(toast)The landmark that holds the stack.::part(toast-action)The action Button of a notification.::part(toast-close)The Close button of a notification.::part(toast-content)The text of a notification: its title and description.::part(toast-description)The description of a notification.::part(toast-icon)The icon of a notification type, or its Spinner while loading.::part(toast-title)The title of a notification.::part(toast-toast)Each notification.::part(toast-viewport)The fixed layer that places the stack at its position.