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.
| Category | Feedback |
|---|---|
| Type | CSS only (.mv-alert) |
| Status | stable |
| Keywords | alert, callout, banner, bandeau, notice, dismissible, message, warning, error |
When to use
- A persistent message about the page or a form must stay visible in place, such as a validation summary
- A warning or error needs a title, explanation and follow-up actions next to the related content
- A full-width site banner announces maintenance, a promotion or a policy change, optionally dismissible
Avoid when
- The feedback is transient and should disappear on its own after an action → use Toast instead
- The user must explicitly confirm before a destructive action proceeds → use Dialog instead
- A list or view has no data to show and needs a guided next step → use Empty instead
Install
node scripts/add.mjs alert --out ./src/marvelousAI 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
| Name | Type | Default | Description |
|---|---|---|---|
data-variant | info | success | warning | danger | banner | (neutral) | Alert tone, or a full-width banner (inverted by default). |
data-color | info | success | warning | danger | accent | Tint independent of the variant (useful on a banner). | |
data-accent | boolean | Colored stripe on the start edge. | |
data-mv-dismiss | on a button | With alert.js: fade, height collapse, then hidden. |
Methods
| Name | Description |
|---|---|
dismissAlert(el) | alert.js export: dismisses an alert programmatically (returns false if canceled). |
Events
| Name | Description |
|---|---|
mv-dismiss | Cancelable, before dismissal. |
mv-dismissed | After dismissal (the element stays in the DOM with hidden). |
CSS classes
| Name | Description |
|---|---|
mv-alert | Container (icon / text / actions grid, container query for the narrow layout). |
mv-alert-icon | Leading <svg>, tinted by variant. |
mv-alert-title / -description | Title and text (the description accepts <p>, <ul>, <a>). |
mv-alert-actions | Buttons on the right, or below the text when the alert is narrower than 34rem. |
mv-alert-close | Close button in the top-right corner (add data-mv-dismiss for the JS animation). |
mv-alert-link | Call-to-action link with an arrow, for banners. |
CSS variables
| Name | Default | Description |
|---|---|---|
--mv-alert-color | Base tint (icon, border and background derive from it). | |
--mv-alert-bg / --mv-alert-border | Explicit background and border. | |
--mv-alert-radius | var(--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.