Skip to main contentSkip to docs navigation

Alert dialogs block the current flow to require an explicit decision or acknowledgment — destructive confirmations, warnings, and error notifications.

@layer components
Requires JavaScript
Viewport queries
Component tokens

Looking for status banners? Unlike many design systems, Chassis calls inline status messages Notifications. This page covers the alert dialog — a <dialog> that blocks the current flow to require an explicit decision.

Introduction

An alert is a <dialog> element styled with .alert and activated by the .dialog plugin. The two classes have distinct responsibilities:

  • .dialog — behavior: animation, backdrop, keyboard handling, and the open/close lifecycle.
  • .alert — visual style: compact flat layout, icon placement, and an action footer.

Alerts are appropriate for destructive-action confirmations (delete, remove, revoke), security verifications before sensitive operations, and error notifications that require acknowledgment before the current flow continues. For informational overlays that do not demand a decision, use Modal. For non-blocking status messages that do not interrupt the current flow, use Notification.

Confirm Delete

Are you sure you want to delete this file? This action cannot be undone.

HTML
<dialog class="alert dialog" id="exampleAlert" role="alertdialog" 
    aria-labelledby="exampleAlertLabel" aria-describedby="exampleAlertBody">
  <svg class="icon icon-danger alert-icon" aria-hidden="true">
    <use xlink:href="#exclamation-triangle-solid"/>
  </svg>
  <div class="alert-body">
    <h2 class="alert-title" id="exampleAlertLabel">Confirm Delete</h2>
    <p id="exampleAlertBody">Are you sure you want to delete this file? This action cannot be undone.</p>
  </div>
  <div class="alert-footer">
    <button type="button" class="button danger">Delete File</button>
    <button type="button" class="button default">Cancel</button>
  </div>
</dialog>

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.

Basic structure

An alert dialog has up to four direct children:

  • .alert-icon — optional icon preceding the body. When present, switches the layout from flex column to a two-column grid (auto 1fr) so the icon and body align side-by-side at medium+. At the small breakpoint the grid reverts to a centered flex column with the icon self-aligned to center.
  • .alert-body — flex column wrapping the title and message text.
    • .alert-title — heading element referenced by aria-labelledby; screen readers announce it when the alert opens.
    • .alert-code — optional <code> element displaying a machine-readable reference string (e.g. an error code) below the title in subdued type (see Error codes).
  • .alert-footer — flex row, right-aligned, containing action buttons.
  • .close-button — optional dismiss button positioned absolute at the block-start / inline-end corner (see Close button).

Alert titles use .alert-title for typography. Typography utilities can further adjust the heading's appearance.

The Dialog plugin's default options allow both backdrop and keyboard dismissal. To prevent dismissal by clicking outside or pressing Escape, add data-cx-backdrop="static" and data-cx-keyboard="false" to the <dialog> element. Most alert dialogs use both attributes.

Live example

To open an alert, add data-cx-toggle="dialog" to any trigger element. For buttons, point at the <dialog> with data-cx-target="#id". For links, set href="#id" instead — data-cx-target is not needed. The example uses data-cx-backdrop="static" and data-cx-keyboard="false" to require an explicit footer action — the backdrop click and Escape key are both disabled.

Show alert

Save Changes?

Do you want to save your changes before leaving the page?

HTML
<button type="button" class="button primary" data-cx-toggle="dialog" data-cx-target="#exampleAlertLive">Show alert</button>
<a href="#exampleAlertLive" class="button link" data-cx-toggle="dialog">Show alert</a>

<!-- Alert -->
<dialog class="alert dialog" id="exampleAlertLive" role="alertdialog" data-cx-backdrop="static" data-cx-keyboard="false"
    aria-labelledby="exampleAlertLiveLabel" aria-describedby="exampleAlertLiveBody">
  <svg class="icon alert-icon" aria-hidden="true"><use href="#info-circle-solid"></use></svg>
  <div class="alert-body">
    <h2 class="alert-title" id="exampleAlertLiveLabel">Save Changes?</h2>
    <p id="exampleAlertLiveBody">Do you want to save your changes before leaving the page?</p>
  </div>
  <div class="alert-footer stacked">
    <button type="button" class="button primary">Save Changes</button>
    <button type="button" class="button default" data-cx-dismiss="dialog">Cancel</button>
    <button type="button" class="button danger outline small:me-auto">Discard</button>
  </div>
</dialog>

Behaviors

Alert dialogs support additional layout patterns for error codes, close buttons, footer configuration, and multi-step flows.

Error codes

The .alert-code class renders a code or reference string below the title in subdued type. Use a <code> element inside .alert-body — the value is a machine-readable identifier and <code> carries the correct semantic.

Error Title

ERR-1234

A comprehensive description of the error.

HTML
<dialog class="alert dialog" id="exampleAlertCode" role="alertdialog"
    aria-labelledby="exampleAlertCodeLabel" 
    aria-describedby="exampleAlertCodeId exampleAlertCodeBody">  
  <svg class="icon icon-danger alert-icon" aria-hidden="true">
    <use xlink:href="#exclamation-circle-solid"/>
  </svg>
  <div class="alert-body">
    <h2 class="alert-title" id="exampleAlertCodeLabel">Error Title</h2>
    <code class="alert-code" id="exampleAlertCodeId">ERR-1234</code>
    <p id="exampleAlertCodeBody">A comprehensive description of the error.</p>
  </div>
  <div class="alert-footer">
    <button type="button" class="button default" data-cx-dismiss="dialog">Close</button>
  </div>
</dialog>

Close button

Alert dialogs typically do not include a close button — the footer actions are the only exit paths, requiring an explicit choice. When an escape path is needed without a footer action, add a .close-button with data-cx-dismiss="dialog" as a direct child of <dialog>.

Dismissible Alert

An alert with an explicit close button allows exiting without taking a footer action.

HTML
<dialog class="alert dialog" id="exampleAlertClose" role="alertdialog"
    aria-labelledby="exampleAlertCloseLabel" aria-describedby="exampleAlertCloseBody">
  <div class="alert-body">
    <h2 class="alert-title" id="exampleAlertCloseLabel">Dismissible Alert</h2>
    <p id="exampleAlertCloseBody">An alert with an explicit close button allows exiting without taking a footer action.</p>
  </div>
  <div class="alert-footer">
    <button type="button" class="button primary">Take Action</button>
    <button type="button" class="button default" data-cx-dismiss="dialog">Cancel</button>
  </div>
  <button type="button" class="close-button" data-cx-dismiss="dialog" aria-label="Close alert"></button>
</dialog>

The .alert-footer uses flex-direction: row-reverse, so buttons are right-aligned without justify-content — write the primary action first in source, it renders on the right. At the small breakpoint, buttons stretch to equal widths (flex: 1). Add .stacked to stack them as full-width columns instead.

For a third action that should be visually separated — such as a destructive option — add .me-auto (or a responsive variant like .small:me-auto) to push it to the opposite end.

Alert with stacked actions

An alert with multiple footer actions, stacking full-width at the small breakpoint.

HTML
<dialog class="alert dialog" id="exampleAlertFooter" role="alertdialog"
    aria-labelledby="exampleAlertFooterLabel" aria-describedby="exampleAlertFooterBody">
  <div class="alert-body">
    <h2 class="alert-title" id="exampleAlertFooterLabel">Alert with stacked actions</h2>
    <p id="exampleAlertFooterBody">An alert with multiple footer actions, stacking full-width at the small breakpoint.</p>
  </div>
  <div class="alert-footer stacked">
    <button type="button" class="button primary">Take Action</button>
    <button type="button" class="button default" data-cx-dismiss="dialog">Cancel</button>
    <button type="button" class="button danger outline small:me-auto">Destructive</button>
  </div>
</dialog>

Sequential alerts

Multiple alert dialogs can be chained by triggering the next dialog from an action inside the current one. The Dialog plugin handles the transition as a swap — the incoming alert opens before the outgoing one closes, keeping the backdrop uninterrupted across the transition.

Delete Account

Are you sure you want to delete your account? This will remove all your data.

Final Confirmation

This action is permanent and cannot be undone. Type "DELETE" below to confirm:

HTML
<button type="button" class="button danger" data-cx-target="#exampleAlertSequential" data-cx-toggle="dialog">Delete Account</button>

<!-- Alert 1 -->
<dialog class="alert dialog" id="exampleAlertSequential" role="alertdialog" data-cx-backdrop="static" data-cx-keyboard="false"
    aria-labelledby="exampleAlertSequentialLabel" aria-describedby="exampleAlertSequentialBody">
  <svg class="icon icon-danger alert-icon" aria-hidden="true"><use href="#exclamation-triangle-solid"></use></svg>
  <div class="alert-body">
    <h2 class="alert-title" id="exampleAlertSequentialLabel">Delete Account</h2>
    <p id="exampleAlertSequentialBody">Are you sure you want to delete your account? This will remove all your data.</p>
  </div>
  <div class="alert-footer">
    <button type="button" class="button danger" data-cx-target="#exampleAlertSequential2" data-cx-toggle="dialog">Delete Account</button>
    <button type="button" class="button default" data-cx-dismiss="dialog">Cancel</button>
  </div>
</dialog>

<!-- Alert 2 -->
<dialog class="alert dialog" id="exampleAlertSequential2" role="alertdialog" data-cx-backdrop="static" data-cx-keyboard="false"
    aria-labelledby="exampleAlertSequentialLabel2" aria-describedby="exampleAlertSequentialBody2">
  <svg class="icon icon-danger alert-icon" aria-hidden="true"><use href="#exclamation-triangle-solid"></use></svg>
  <div class="alert-body">
    <h2 class="alert-title" id="exampleAlertSequentialLabel2">Final Confirmation</h2>
    <p id="exampleAlertSequentialBody2">This action is permanent and cannot be undone. Type "<strong>DELETE</strong>" below to confirm:</p>
    <input type="text" class="form-input" placeholder="Type DELETE to confirm" aria-label="Type DELETE to confirm" />
  </div>
  <div class="alert-footer">
    <button type="button" class="button danger" disabled>Confirm Delete</button>
    <button type="button" class="button default" data-cx-dismiss="dialog">Cancel</button>
    <button type="button" class="button link small:me-auto" data-cx-toggle="dialog" data-cx-target="#exampleAlertSequential">Go Back</button>
  </div>
</dialog>

Accessibility

The native <dialog> element carries an implicit dialog role. Add aria-labelledby pointing to the .alert-title element's id so assistive technologies announce the alert heading when it opens.

For decision-forcing alerts where the current flow is blocked until the user responds, add role="alertdialog" to the <dialog> element. The alertdialog role requires both aria-labelledby (pointing to the title) and aria-describedby (pointing to the message body).

HTML
<dialog class="alert dialog" role="alertdialog"
  aria-labelledby="confirmTitle"
  aria-describedby="confirmBody"
  data-cx-backdrop="static" data-cx-keyboard="false">
  <div class="alert-body">
    <h2 class="alert-title" id="confirmTitle">Confirm Delete</h2>
    <p id="confirmBody">This action cannot be undone.</p>
  </div>
  ...
</dialog>

Focus moves to the dialog element on open and is trapped inside until dismissed. To move focus to a specific element on open, listen to shown.cx.dialog or add autofocus to the target element:

JavaScript
document.getElementById('myAlert').addEventListener('shown.cx.dialog', () => {
  document.getElementById('confirmButton').focus()
})

JavaScript API

Alert dialogs use the Dialog plugin — the same plugin as Modal. Import the Dialog class:

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

Triggers

The data-attribute API opens and closes alert dialogs without writing JavaScript:

HTML
<!-- Trigger button -->
<button data-cx-toggle="dialog" data-cx-target="#myAlert">Open alert</button>

<!-- Alert element with non-dismissible options -->
<dialog class="alert dialog"
        data-cx-backdrop="static"
        data-cx-keyboard="false">
  ...
  <button data-cx-dismiss="dialog">Cancel</button>
</dialog>

For options, methods, and events, see the Modal JavaScript API.

CSS

The Alert component can be customized through Sass variables at compile time.

Custom properties

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

--zindex: var(--alert-zindex, #{$zindex-alert});
--width: var(--alert-width, #{$alert-width});
--padding-y: var(--alert-padding-y, #{$alert-large-padding-y});
--padding-x: var(--alert-padding-x, #{$alert-large-padding-x});
--gap: var(--alert-gap, #{$alert-large-main-gap});
--fg-color: var(--alert-fg-color, #{$alert-fg-color});
--bg-color: var(--alert-bg-color, #{$alert-bg-color});
--border-width: var(--alert-border-width, #{$alert-border-width});
--border-color: var(--alert-border-color, #{$alert-border-color});
--border-radius: var(--alert-border-radius, #{$alert-border-radius});
--box-shadow: var(--alert-box-shadow, #{$alert-box-shadow});
@include map-font($alert-large-font-body, alert-message);
@include map-font($alert-large-font-title, alert, title);
@include map-font($alert-code-font, alert, code);
--code-color: var(--alert-code-color, #{$alert-code-color});
--body-gap: var(--alert-body-gap, #{$alert-large-body-gap});
--footer-large-gap: var(--alert-footer-large-gap, #{$alert-footer-large-gap});
--footer-small-gap: var(--alert-footer-small-gap, #{$alert-footer-small-gap});
--close-button-size: var(--alert-close-button-size, #{$alert-close-button-size});
--close-button-inset: var(--alert-close-button-inset, #{$alert-close-button-inset});
--dialog-transition-transform: #{$dialog-transition-transform};
--dialog-transition-duration: #{$dialog-transition-duration};
--dialog-transition-timing: #{$dialog-transition-timing};
--dialog-backdrop-bg: #{$dialog-backdrop-bg};
--dialog-backdrop-blur: #{$dialog-backdrop-blur};
--dialog-margin: #{$dialog-margin};

Sass variables

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

$alert-width:                       $modal-medium-width;
$alert-code-font:                   $font-code-small-normal;
$alert-code-color:                  var(--fg-subtle);
$alert-fg-color:                    $modal-fg-color;
$alert-bg-color:                    $modal-bg-color;
$alert-border-color:                $modal-border-color;
$alert-footer-large-gap:            $modal-footer-large-gap;
$alert-footer-small-gap:            $modal-footer-small-gap;
$alert-close-button-size:           var(--icon-small);
$alert-close-button-inset:          var(--space-medium);

See the Modal page for backdrop and transition variables shared with alert dialogs.