Skip to main contentSkip to docs navigation

Display temporary, non-blocking notifications using the Toast plugin — suitable for status updates and non-critical alerts.

@layer components
Requires JavaScript
Context tokens

Introduction

Toasts are short-lived, non-blocking notifications that overlay page content. Unlike the notification component, toasts are transient — they appear briefly and either hide automatically or are dismissed by the user.

How they work

The Toast plugin manages visibility through CSS classes. Toasts start hidden and require a .show() call — or a data-cx-dismiss trigger — to appear. When autohide is enabled, the hide timer starts after the show transition completes and pauses while the pointer is over the toast or focus is within it. Toasts overlay content without disrupting pointer events on the page underneath.

Chassis CSS respects user accessibility preferences by automatically disabling animations when the prefers-reduced-motion media query is detected. See the reduced motion guidelines in our accessibility documentation for implementation details.

Live example

Clicking the button below instantiates a Toast and calls .show(). The toast auto-hides after 5 seconds (the default delay).

Chassis11 mins ago

Hello, world! This is a toast message.

const toastTrigger = document.getElementById('liveToastButton')
const toastLiveExample = document.getElementById('liveToast')

if (toastTrigger) {
  const toastChassis = Toast.getOrCreateInstance(toastLiveExample)
  toastTrigger.addEventListener('click', () => {
    toastChassis.show()
  })
}

Basic structure

A toast consists of a .toast element wrapping any combination of .toast-header, .toast-body, and .toast-footer regions. The header and footer carry border rules that separate them visually from the body.

Chassis 11 mins ago
Hello, world! This is a toast message.
HTML
<div class="toast" role="status">
  <div class="toast-header">
    <img src="..." class="rounded me-xsmall" alt="...">
    <strong class="me-auto">Chassis</strong>
    <small>11 mins ago</small>
    <button type="button" class="close-button" data-cx-dismiss="toast" aria-label="Close"></button>
  </div>
  <div class="toast-body">
    Hello, world! This is a toast message.
  </div>
</div>

.toast-header is a flex container. Chassis's margin and spacing utilities apply directly for alignment and spacing control.

.toast-footer creates a button row below the body, separated by a border that matches the header rule. Use it when the notification requires user acknowledgement or a follow-up action.

Hello, world! This is a toast message.
HTML
<div class="toast" role="status">
  <div class="toast-body">
    Hello, world! This is a toast message.
  </div>
  <div class="toast-footer">
    <button type="button" class="button primary small">Take action</button>
    <button type="button" class="button secondary small" data-cx-dismiss="toast">Close</button>
  </div>
</div>

Simplified layout

Remove .toast-header and apply flexbox utilities directly to .toast for a compact, single-region layout.

Hello, world! This is a toast message.
HTML
<div class="toast justify-content-between" role="status">
  <div class="d-flex">
    <div class="toast-body">
      Hello, world! This is a toast message.
    </div>
    <button type="button" class="close-button m-small ms-auto" data-cx-dismiss="toast" aria-label="Close"></button>
  </div>
</div>

Placement

.toast-container is position: absolute by default. Combine it with position utilities to pin toasts to a viewport edge (position-fixed) or to a corner within a relatively-positioned ancestor. Add a spacing utility to keep toasts from touching the container edge.

HTML
<div class="toast-container p-medium">
  <div class="toast show" role="alert" aria-live="assertive" aria-atomic="true">
    <div class="toast-header">
      <img src="..." class="rounded me-xsmall" alt="...">
      <strong class="me-auto">Chassis</strong>
      <small>11 mins ago</small>
    </div>
    <div class="toast-body">
      Hello, world! This is a toast message.
    </div>
  </div>
</div>

Stacking

Toasts inside a .toast-container stack vertically, separated by --toast-spacing (derived from $container-padding-x). The container itself uses width: max-content so it sizes to the widest toast.

Chassis just now
See? Just like this.
Chassis 2 seconds ago
Heads up, toasts will stack automatically.
HTML
<div class="toast-container position-static">
  <div class="toast" role="status">
    <div class="toast-header">
      <img src="..." class="rounded me-xsmall" alt="...">
      <strong class="me-auto">Chassis</strong>
      <small class="fg-subtle">just now</small>
      <button type="button" class="close-button" data-cx-dismiss="toast" aria-label="Close"></button>
    </div>
    <div class="toast-body">
      See? Just like this.
    </div>
  </div>

  <div class="toast" role="status">
    <div class="toast-header">
      <img src="..." class="rounded me-xsmall" alt="...">
      <strong class="me-auto">Chassis</strong>
      <small class="fg-subtle">2 seconds ago</small>
      <button type="button" class="close-button" data-cx-dismiss="toast" aria-label="Close"></button>
    </div>
    <div class="toast-body">
      Heads up, toasts will stack automatically.
    </div>
  </div>
</div>

Notification regions

For UIs that generate multiple notifications, wrap .toast-container in an aria-live region and position the container with inset utilities. The container sits outside normal document flow, so toasts append without shifting page content.

Chassis just now
See? Just like this.
Chassis 2 seconds ago
Heads up, toasts will stack automatically.
HTML
<div aria-live="polite" aria-atomic="true" class="position-relative">
  <div class="toast-container top-0 end-0 p-medium">
    <div class="toast" role="status">
      <div class="toast-header">
        <img src="..." class="rounded me-xsmall" alt="...">
        <strong class="me-auto">Chassis</strong>
        <small class="fg-subtle">just now</small>
        <button type="button" class="close-button" data-cx-dismiss="toast" aria-label="Close"></button>
      </div>
      <div class="toast-body">
        See? Just like this.
      </div>
    </div>

    <div class="toast" role="status">
      <div class="toast-header">
        <img src="..." class="rounded me-xsmall" alt="...">
        <strong class="me-auto">Chassis</strong>
        <small class="fg-subtle">2 seconds ago</small>
        <button type="button" class="close-button" data-cx-dismiss="toast" aria-label="Close"></button>
      </div>
      <div class="toast-body">
        Heads up, toasts will stack automatically.
      </div>
    </div>
  </div>
</div>

Theming

Toasts inherit the context color system and the translucent background variant from the Chassis component layer.

Context variants

Apply .context and a context color class to tint the toast. Add .solid for full-color backgrounds with inverted text.

Chassis just now
See? Just like this.
Chassis 2 seconds ago
Heads up, toasts will stack automatically.
HTML
<div class="toast-container position-static">
  <div class="toast context primary" role="status">
    <div class="toast-header">
      <img src="..." class="rounded me-xsmall" alt="...">
      <strong class="me-auto">Chassis</strong>
      <small class="fg-main">just now</small>
      <button type="button" class="close-button" data-cx-dismiss="toast" aria-label="Close"></button>
    </div>
    <div class="toast-body">
      See? Just like this.
    </div>
  </div>

  <div class="toast context primary solid" role="status">
    <div class="toast-header">
      <img src="..." class="rounded me-xsmall" alt="...">
      <strong class="me-auto">Chassis</strong>
      <small class="fg-main">2 seconds ago</small>
      <button type="button" class="close-button" data-cx-dismiss="toast" aria-label="Close"></button>
    </div>
    <div class="toast-body">
      Heads up, toasts will stack automatically.
    </div>
  </div>
</div>

Translucent

.translucent applies a semi-transparent background. Use it when toasts appear over rich or patterned content.

Chassis 11 mins ago
Hello, world! This is a toast message.
HTML
<div class="toast translucent" role="status">
  <div class="toast-header">
    <img src="..." class="rounded me-xsmall" alt="...">
    <strong class="me-auto">Chassis</strong>
    <small class="fg-subtle">11 mins ago</small>
    <button type="button" class="close-button" data-cx-dismiss="toast" aria-label="Close"></button>
  </div>
  <div class="toast-body">
    Hello, world! This is a toast message.
  </div>
</div>

Chassis CSS respects user accessibility preferences by automatically disabling translucency effects when the prefers-reduced-transparency media query is detected. Note that this media feature is currently only supported in Chromium-based browsers — Safari and Firefox do not yet implement it.

Color utilities

Chassis color and background utilities apply directly to .toast. Pair a border utility with matching foreground and background classes for semantic coloring.

HTML
<div class="toast border-danger bg-white fg-danger justify-content-between" role="alert">
  <div class="d-flex">
    <div class="toast-body">
      Hello, world! This is a toast message.
    </div>
    <button type="button" class="close-button fg-black m-small ms-auto" data-cx-dismiss="toast" aria-label="Close"></button>
  </div>
</div>

Accessibility

Toasts carry live-region semantics that drive screen reader announcements. The role, timing, and interactive-element decisions here determine whether assistive technology users receive the notification at all.

ARIA roles

The ARIA role determines announcement urgency. Most toasts convey confirmations or informational updates — use role="status" for those. Reserve role="alert" for errors and messages requiring immediate attention, such as failed operations or session timeouts. Both roles carry implicit aria-live semantics, so no separate aria-live attribute is needed.

See the notification component's ARIA roles section for a full breakdown, including a heuristic table by context variant.

Autohide timing

The autohide timer starts after the show transition completes and pauses whenever the pointer is over the toast or focus is within it — the countdown resumes only after both leave. Set delay to a value that gives users enough time to read the full message before the timer begins. For toasts with action buttons, set autohide: false and provide a close button so users control dismissal.

Chassis 11 mins ago
Hello, world! This is a toast message.
HTML
<div class="toast" role="status" data-cx-autohide="false">
  <div class="toast-header">
    <img src="..." class="rounded me-xsmall" alt="...">
    <strong class="me-auto">Chassis</strong>
    <small>11 mins ago</small>
    <button type="button" class="close-button" data-cx-dismiss="toast" aria-label="Close"></button>
  </div>
  <div class="toast-body">
    Hello, world! This is a toast message.
  </div>
</div>

Avoid placing interactive controls — buttons, links — inside auto-hiding toasts. Keyboard and screen reader users may not have enough time to reach or activate them before the toast disappears.

When to use alternatives

For form validation errors or information users must act on before continuing, use the notification component instead. Notifications persist until dismissed and support inline placement near the content they describe.

JavaScript API

The Toast plugin handles show/hide transitions and autohide timing. Import the Toast class from the Chassis module:

JavaScript
import { Toast } from '@chassis-ui/css'

Triggers

The data-attribute API wires up dismissal without any JavaScript on the page beyond the bundled plugin:

Enable dismissal with the data-cx-dismiss attribute on a button within the toast:

HTML
<button type="button" class="close-button" data-cx-dismiss="toast" aria-label="Dismiss"></button>

Or on a button outside the toast using the additional data-cx-target attribute:

HTML
<button type="button" class="close-button" data-cx-dismiss="toast" data-cx-target="#my-toast" aria-label="Dismiss toast"></button>
When a toast is dismissed, it is completely removed from the DOM. If you need to maintain focus management for accessibility, listen for the closed.cx.toast event to set focus to an appropriate element.

Initialization

For programmatic control — calling methods or listening to events — instantiate each .toast element with the Toast class:

JavaScript
const toastElements = document.querySelectorAll('.toast')
const toasts = [...toastElements].map(element => new Toast(element, options))

For dismiss-only functionality, manual initialization is not required. data-cx-dismiss="toast" initializes the plugin automatically on first interaction.

See the triggers section for details.

Options

Options are set via data-cx-* attributes or passed to the constructor as an object. Attribute names use the kebab-case form of the option name — data-cx-custom-class, not data-cx-customClass. Attribute values are parsed to their native types:"true"true, "0"0, and valid JSON strings to objects.

Use data-cx-config to pass multiple options as a JSON string:data-cx-config='{"delay":200}'. Individual data-cx-* attributes take precedence over data-cx-config. You can also use JSON values in individual attributes, such as data-cx-delay='{"show":100,"hide":200}'.

When initializing components, Chassis merges configurations from multiple sources in this priority order: default settings, data-cx-config values, individual data-cx-*attributes, and finally any JavaScript object options. Values defined later in this sequence override earlier ones.

NameTypeDefaultDescription
animationbooleantrueApplies a CSS fade transition on show and hide.
autohidebooleantrueHides the toast automatically after delay milliseconds. The timer pauses while the pointer is over the toast or focus is within it.
delaynumber5000Milliseconds to wait before hiding. Only applies when autohide is true.

Methods

The plugin exposes five instance methods and two static lookup methods for programmatic control:

All Chassis CSS component methods are asynchronous and initiate CSS transitions. Methods return immediately when the transition begins, not when it completes. Calling methods on components that are already transitioning will be ignored to prevent conflicts. Learn more about Chassis JavaScript patterns.

MethodDescription
disposeDestroys the instance and removes stored data from the element.
getInstanceStatic — returns the existing instance bound to a DOM element, or null. Example: Toast.getInstance(element)
getOrCreateInstanceStatic — returns the existing instance or creates one. Example: Toast.getOrCreateInstance(element)
hideBegins the hide transition. Returns immediately; listen for hidden.cx.toast for completion.
isShownReturns true if the toast currently has the .show class.
showBegins the show transition. Returns immediately; listen for shown.cx.toast for completion.
toggleCalls show() if hidden, hide() if shown.
JavaScript
import { Toast } from '@chassis-ui/css'

const toast = Toast.getOrCreateInstance('#myToast')
toast.show()
toast.hide()

if (toast.isShown()) {
  toast.toggle()
}

Events

Each lifecycle transition fires a pair of events — one immediately when the method is called and one when the transition ends. Listen on the .toast element itself.

EventDescription
hide.cx.toastFired immediately when hide() is called.
hidden.cx.toastFired when the hide transition has completed.
show.cx.toastFired immediately when show() is called.
shown.cx.toastFired when the show transition has completed.
JavaScript
import { Toast } from '@chassis-ui/css'

const toastElement = document.getElementById('myToast')

toastElement.addEventListener('hidden.cx.toast', () => {
  // hide transition complete — clean up or queue the next notification
})

toastElement.addEventListener('shown.cx.toast', () => {
  // show transition complete — start any timers or tracking
})

CSS

This component can be customized through Sass variables at compile time.

Custom properties

This component exposes CSS custom properties to control its appearance at runtime.

--padding-y: var(--toast-padding-y, #{$toast-padding-y});
--padding-x: var(--toast-padding-x, #{$toast-padding-x});
--spacing: var(--toast-spacing, #{$toast-spacing});
--max-width: var(--toast-max-width, #{$toast-max-width});
@include clamp($toast-font-size, --font-size);
--fg-color: var(--toast-fg-color, #{$toast-fg-color});
--bg-color: var(--toast-bg-color, #{$toast-bg-color});
--border-width: var(--toast-border-width, #{$toast-border-width});
--border-color: var(--toast-border-color, #{$toast-border-color});
--border-radius: var(--toast-border-radius, #{$toast-border-radius});
--box-shadow: var(--toast-box-shadow, #{$toast-box-shadow});
--header-fg-color: var(--toast-header-fg-color, #{$toast-header-fg-color});
--header-bg-color: var(--toast-header-bg-color, #{$toast-header-bg-color});
--header-border-color: var(--toast-header-border-color, #{$toast-header-border-color});

Sass variables

This component uses Sass variables in scss/config/_defaults.scss to define its defaults.

$toast-max-width:                   22.5rem; //360px;
$toast-padding-x:                   .75rem;
$toast-padding-y:                   .5rem;
$toast-font-size:                   .875rem;
$toast-fg-color:                    var(--fg-main);
// $toast-bg-color:                    #{to-opacity(var(--bg-main), var(--opacity-dim-main))};
$toast-bg-color:                    var(--bg-main);
$toast-border-width:                var(--border-width-medium);
$toast-border-color:                var(--border-subtle);
$toast-border-radius:               var(--border-radius-medium);
$toast-box-shadow:                  var(--box-shadow-medium);
$toast-spacing:                     $container-padding-x;

$toast-header-fg-color:             var(--fg-main);
$toast-header-bg-color:             var(--dim-slight);
$toast-header-border-color:         $toast-border-color;