Alert Stack
4.38 KB gzip3.84 KB brotli4.52 KB zstdPopover, @starting-style and user-select are not yet Baseline widely available.
Works in Chrome 117+, Edge 117+, Firefox 129+, Safari 17.5+.
Why these versions:
- @starting-style needs
Chrome 117+,Edge 117+,Firefox 129+andSafari 17.5+.
Partially supported:
- Popover — Safari on iOS ships it partially before 18.3.
- Nesting (nesting) — Chrome, Chrome Android and Edge ship it partially before 120.
- user-select — Safari and Safari on iOS need the
-webkit-user-selectspelling, which the component ships.
sv-alert-stack displays stackable alerts on the page's top layer.
Use a single alert stack per document. Multiple stacks compete over the keyboard shortcut and focus.
Usage
The element renders nothing on its own; alerts are created from script:
<sv-alert-stack></sv-alert-stack>const alertStack = document.querySelector("sv-alert-stack");
alertStack.create({ severity: "error", title: "File not found", description: "The file at /path/to/file does not exist",});The stack expands on hover, on tap, and when an alert receives keyboard focus. Auto-dismiss timers pause while it is expanded.
Position and offset
Combine one vertical attribute with one horizontal attribute:
<sv-alert-stack top end></sv-alert-stack>Offset the stack from the viewport edge by padding the wrapper part:
sv-alert-stack::part(wrapper) { padding-block-start: 2rem; padding-inline-end: 2rem;}Swipe to dismiss
Swiping is enabled on the stack, not per alert:
<sv-alert-stack swipe-dismiss></sv-alert-stack>The swipeToDismiss option then opts a single alert out of it.
Custom actions and icons
An actionButton.action replaces the default dismissal, so dismiss the alert once the work is done:
const dismiss = alertStack.create({ title: "Export ready", actionButton: { label: "Download", action: () => { downloadFile(); dismiss(); }, },});iconOverride replaces the severity icon. Return nothing to keep the default icon for that severity.
The icon renders inside the shadow DOM, so give it a part attribute when it needs external styling:
alertStack.create({ severity: "success", title: "Export ready", iconOverride: () => { const icon = document.createElement("span"); icon.part = "icon icon-success"; icon.textContent = "OK"; return icon; },});sv-alert-stack::part(icon-success) { color: var(--sv-success);}Accessibility
Alerts with severity "error" are announced as role="alert", the rest as role="status". Alerts created before the page finishes loading are not announced.
An appearing alert never takes keyboard focus, so its buttons can be far away in tab order. The shortcut attribute, Alt+T by default, focuses the first alert and expands the stack. Escape collapses the stack and restores the previous focus.
The element is a region labelled "Notifications". Set aria-label on it to rename it.
Give auto-dismissing alerts enough time to be read. Frequent or rapid alerts overwhelm users relying on assistive technologies.
Structure
olwrapper
lialert - One per alert, added and removed at runtime
div
div
API References
Methods
create()
Creates an item and adds it to the stack.
Returns a function that dismisses and removes the item.
export type ItemOptions = { // The id of the item. id?: string;
// The severity of the item. // Default: "info" severity?: Severity;
// The title of the item. // Default: severity.toUpperCase() title?: string;
// The message of the item. // Default: "" description?: string;
// The time before auto dismissing the item in milliseconds. Use `-1` to disable auto dismiss. // Default: -1 duration?: number;
// Whether this item can be dismissed with a swipe gesture. // Default: true swipeToDismiss?: boolean;
// Whether to show an action button. // Use `null` to remove the action button. actionButton?: null | { // The text of the action button. // Default: "Dismiss" label?: string;
// The click event handler. // Default: dismiss the item action?: (event: MouseEvent) => void; };
// Optional function to provide a custom icon element. // // If provided, this function receives the item's `severity` and // should return an `HTMLElement` to replace the default severity icon. // // Allows full customization of the icon, including animated or complex elements. iconOverride?: (severity: Severity) => HTMLElement;};Properties
items
All item elements within the container.
maxExpandedItems
The number of items shown when the stack is expanded.
A hidden item with keyboard focus is temporarily brought to the front, then returned when focus leaves it.
maxItems
The maximum number of items allowed in the stack.
When this limit is exceeded, the oldest item is removed.
swipeDismiss
Whether items can be dismissed by swiping them horizontally.
shortcut
Keyboard shortcut used to focus and expand the stack.
The shortcut is written as a + separated string, such as "Alt+T" or "Alt+Shift+T".
Attributes
"top"
Positions the stack at the top of the page
"bottom"
Has no effect because the stack is positioned at the bottom by default
"start"
Positions the stack on the start side of the screen (left in LTR, right in RTL)
"center"
Positions the stack in the center of the screen
"end"
Has no effect because the stack is positioned on the end side by default (right in LTR, left in RTL)
"max-items"
The maximum number of items allowed in the stack.
When this limit is exceeded, the oldest item is removed.
"max-expanded-items"
The number of items shown when the stack is expanded.
A hidden item with keyboard focus is temporarily brought to the front, then returned when focus leaves it.
"shortcut"
Keyboard shortcut used to focus and expand the stack.
The shortcut is written as a + separated string, such as "Alt+T" or "Alt+Shift+T".
"swipe-dismiss"
Whether items can be dismissed by swiping them horizontally.
Events
dismissed
Fired when the user dismisses an alert using its action button or a swipe, before it is removed. Cancel it to keep the alert.
itemschange
Fired when an alert is added or removed. A removed alert is gone from items right away, even while it is still visible.
CSS Properties
| Name | Description | Default |
|---|---|---|
--_d | Stack expansion direction: 1: bottom to top. -1: top to bottom. | 1 |
--sv-success | Color for success icons and titles | AccentColor |
--sv-error | Color for error icons and titles | AccentColor |
--sv-info | Color for info icons and titles | AccentColor |
--sv-warning | Color for warning icons and titles | AccentColor |
--sv-alert-stack-bg | The background color of the items. | --sv-gray-6 |
--sv-alert-stack-bdr-clr | The border color of the items. | --sv-gray-5 |
--sv-alert-stack-bdr-rad | The border radius of the items. | --sv-bdr-rad-md |
--sv-alert-stack-bdr-sz | The border size of the items. | --sv-bdr-sz-sm |
--sv-alert-stack-btn-bg | The background color of the dismiss action button. | --sv-gray-5 |
--sv-alert-stack-btn-bdr-rad | The border radius of the dismiss action button. | --sv-bdr-rad-sm |
--sv-alert-stack-dur | The duration of stack animations. | 300ms |
--sv-alert-stack-ease | The easing function used by stack animations. | cubic-bezier(0.25, 1, 0.5, 1) |
CSS Parts
| Name | Description |
|---|---|
::part(wrapper) | Cards container element. |
::part(alert) | The card container element. |
::part(icon) | The icon svg element. |
::part(title) | The title element. |
::part(action-button) | The action button element. |
::part(description) | The description element. |