Alert — .mv-alert

Pure-CSS callouts (neutral, info, success, warning, danger) with an icon, title, description and actions that wrap below the text at narrow widths, a full-width banner, and an optional animated dismiss in a few lines of JS.

CategoryFeedback
TypeCSS only (.mv-alert)
Statusstable
Keywordsalert, callout, banner, bandeau, notice, dismissible, message, warning, error

When to use

Avoid when

Install

node scripts/add.mjs alert --out ./src/marvelous

AI agent with the Marvelous UI MCP server: install_components({ slugs: ["alert"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Files copied (dependencies included): tokens/tokens.css, core/base.css, core/motion.js, components/alert/alert.css, components/alert/alert.js.

Usage

Canonical markup — start from it and customize with attributes, data-* and CSS variables:

<div style="display:grid;gap:.875rem;width:100%;max-width:44rem;margin-inline:auto">
  <!-- Banners -->
  <div class="mv-alert" data-variant="banner" style="border-radius:var(--mv-radius-lg)">
    <span class="mv-alert-title">New: shared dashboards</span>
    <span class="mv-alert-description">Invite your team in one click.</span>
    <a class="mv-alert-link" href="#">Learn more<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></a>
    <button class="mv-alert-close" data-mv-dismiss aria-label="Dismiss announcement"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
  </div>

  <!-- Neutral -->
  <div class="mv-alert">
    <svg class="mv-alert-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 17l6-6-6-6M12 19h8"/></svg>
    <p class="mv-alert-title">Shortcut available</p>
    <p class="mv-alert-description">Open the command palette with <kbd style="font:inherit;font-family:var(--mv-font-mono);font-size:.75rem;padding:1px 5px;border:1px solid var(--mv-border);border-radius:4px">Ctrl K</kbd> from any page.</p>
  </div>

  <!-- Info with actions -->
  <div class="mv-alert" data-variant="info">
    <svg class="mv-alert-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></svg>
    <p class="mv-alert-title">An update is available</p>
    <p class="mv-alert-description">Version 4.2 fixes PDF export and speeds up search.</p>
    <div class="mv-alert-actions">
      <button class="mv-button" data-variant="ghost" data-size="sm">Later</button>
      <button class="mv-button" data-size="sm">Update now</button>
    </div>
  </div>

  <!-- Success, dismissible -->
  <div class="mv-alert" data-variant="success" role="status">
    <svg class="mv-alert-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m8.5 12 2.5 2.5 4.5-5"/></svg>
    <p class="mv-alert-title">Payment confirmed</p>
    <p class="mv-alert-description">Invoice #2026-0914 was sent to [email protected].</p>
    <button class="mv-alert-close" data-mv-dismiss aria-label="Dismiss"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
  </div>

  <!-- Warning with a list -->
  <div class="mv-alert" data-variant="warning">
    <svg class="mv-alert-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0zM12 9v4M12 17h.01"/></svg>
    <p class="mv-alert-title">Your password must contain:</p>
    <div class="mv-alert-description">
      <ul>
        <li>at least 12 characters;</li>
        <li>an uppercase letter and a number.</li>
      </ul>
    </div>
  </div>

  <!-- Danger, urgent -->
  <div class="mv-alert" data-variant="danger" data-accent role="alert">
    <svg class="mv-alert-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 8v4M12 16h.01"/></svg>
    <p class="mv-alert-title">Sync failed</p>
    <p class="mv-alert-description">Can’t reach the server since 2:02 p.m. Your changes are saved locally. <a href="#">View service status</a></p>
  </div>

  <!-- Tinted banner -->
  <div class="mv-alert" data-variant="banner" data-color="accent" style="border-radius:var(--mv-radius-lg);border-width:1px">
    <svg class="mv-alert-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l1.9 5.8H20l-4.9 3.6 1.9 5.8L12 14.6l-4.9 3.6 1.9-5.8L4 8.8h6.1z"/></svg>
    <span class="mv-alert-title">30% off the annual plan</span>
    <span class="mv-alert-description">through Sep 30</span>
    <a class="mv-alert-link" href="#">Claim offer<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6"/></svg></a>
  </div>
</div>

API

Attributes

NameTypeDefaultDescription
data-variantinfo | success | warning | danger | banner(neutral)Alert tone, or a full-width banner (inverted by default).
data-colorinfo | success | warning | danger | accentTint independent of the variant (useful on a banner).
data-accentbooleanColored stripe on the start edge.
data-mv-dismisson a buttonWith alert.js: fade, height collapse, then hidden.

Methods

NameDescription
dismissAlert(el)alert.js export: dismisses an alert programmatically (returns false if canceled).

Events

NameDescription
mv-dismissCancelable, before dismissal.
mv-dismissedAfter dismissal (the element stays in the DOM with hidden).

CSS classes

NameDescription
mv-alertContainer (icon / text / actions grid, container query for the narrow layout).
mv-alert-iconLeading <svg>, tinted by variant.
mv-alert-title / -descriptionTitle and text (the description accepts <p>, <ul>, <a>).
mv-alert-actionsButtons on the right, or below the text when the alert is narrower than 34rem.
mv-alert-closeClose button in the top-right corner (add data-mv-dismiss for the JS animation).
mv-alert-linkCall-to-action link with an arrow, for banners.

CSS variables

NameDefaultDescription
--mv-alert-colorBase tint (icon, border and background derive from it).
--mv-alert-bg / --mv-alert-borderExplicit background and border.
--mv-alert-radiusvar(--mv-radius-lg)Radius.

Accessibility

Static alert: no role (or role="note"). Dynamically inserted message: role="status" (polite) or role="alert" (urgent, errors only). Icons are aria-hidden; the title carries the meaning. The close button has an aria-label; after dismissal, focus moves to the next element. Reduced motion: instant dismissal.