Skip to content

Alert Stack

4.38 KB gzip3.84 KB brotli4.52 KB zstd Baseline 2024 Newly available

Popover, @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+ and Safari 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-select spelling, which the component ships.

sv-alert-stack displays stackable alerts on the page's top layer.

Warning

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
svgicon - Swapped out by iconOverride
divtitle
buttonaction-button
divdescription

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.