Alert
A contextual feedback strip.
Tones
A tone is required. Pair .alert with .alert--neutral for the plain surface look, or with an intent like .alert--success for a tinted variant. A bare .alert renders transparent, the same contract as .btn.
<div class="demo-stack">
<div class="alert alert--neutral">
<i data-lucide="info"></i>
<div>Some neutral message here.</div>
</div>
<div class="alert alert--primary">
<i data-lucide="info"></i>
<div>Heads up, your trial ends in 3 days.</div>
</div>
<div class="alert alert--success">
<i data-lucide="check-circle-2"></i>
<div>Your changes have been saved successfully.</div>
</div>
<div class="alert alert--warning">
<i data-lucide="triangle-alert"></i>
<div>Some features may not work.</div>
</div>
<div class="alert alert--danger">
<i data-lucide="x-circle"></i>
<div>Payment failed. Check your card details.</div>
</div>
<div class="alert alert--info">
<i data-lucide="info"></i>
<div>Some useful information here.</div>
</div>
</div>Without icon
There's no icon wrapper class. The leading icon is any direct <svg> or <i> child. Skip it and the row reflows around the text.
<div class="demo-stack">
<div class="alert alert--neutral">Heads up, your trial ends in 3 days.</div>
<div class="alert alert--success">Your changes have been saved successfully.</div>
</div>With heading and description
Add .alert__description for a stacked layout. The heading sits above the description, the icon aligns with the heading, and the row gains a bit of breathing room.
<div class="alert alert--neutral">
<i data-lucide="info"></i>
<div class="alert__heading">Alert Title</div>
<div class="alert__description">Alert Description</div>
</div>Same layout, with an intent.
<div class="demo-stack">
<div class="alert alert--info">
<i data-lucide="info"></i>
<div class="alert__heading">Heads up</div>
<div class="alert__description">A new version is available. Refresh to load it.</div>
</div>
<div class="alert alert--warning">
<i data-lucide="triangle-alert"></i>
<div class="alert__heading">Unsaved changes</div>
<div class="alert__description">Leaving this page will discard your edits.</div>
</div>
<div class="alert alert--danger">
<i data-lucide="x-circle"></i>
<div class="alert__heading">Payment failed</div>
<div class="alert__description">We couldn't charge your card. Update billing details and retry.</div>
</div>
</div>Action slot
.alert__action is the trailing slot. It pushes to the right on single-line alerts and centers vertically when a description is present. Drop in a button, link, or any control.
<div class="alert alert--neutral">
<i data-lucide="info"></i>
<div>Message deleted successfully.</div>
<div class="alert__action">
<button type="button" class="btn btn--neutral btn--sm">Undo</button>
</div>
</div>Multiple actions and intent variants.
<div class="demo-stack">
<div class="alert alert--warning">
<i data-lucide="triangle-alert"></i>
<div>Your session is about to expire.</div>
<div class="alert__action">
<button type="button" class="btn btn--ghost btn--neutral btn--sm">Stay</button>
<button type="button" class="btn btn--neutral btn--sm">Extend</button>
</div>
</div>
<div class="alert alert--info">
<i data-lucide="info"></i>
<div class="alert__heading">New version available</div>
<div class="alert__description">Reload to pick up the latest changes.</div>
<div class="alert__action">
<button type="button" class="btn btn--primary btn--sm">Reload</button>
</div>
</div>
</div>Dismissible
Alert ships no special close control. Drop a .btn--ghost.btn--neutral.btn--icon-only.btn--sm with an X icon inside .alert__action. JS to close the alert is wired in Step 4; today the button is markup-only.
<div class="demo-stack">
<div class="alert alert--success">
<i data-lucide="check-circle-2"></i>
<div>Your changes have been saved.</div>
<div class="alert__action">
<button type="button" class="btn btn--ghost btn--neutral btn--icon-only btn--sm" aria-label="Dismiss">
<i data-lucide="x"></i>
</button>
</div>
</div>
<div class="alert alert--danger">
<i data-lucide="x-circle"></i>
<div class="alert__heading">Couldn't connect</div>
<div class="alert__description">We lost contact with the server. Try again in a moment.</div>
<div class="alert__action">
<button type="button" class="btn btn--ghost btn--neutral btn--icon-only btn--sm" aria-label="Dismiss">
<i data-lucide="x"></i>
</button>
</div>
</div>
</div>Inline link
.alert__link reads --alert-link-color. That resolves to primary on a neutral alert and to the intent color on tinted alerts, so the link affordance stays readable regardless of tone.
<div class="demo-stack">
<div class="alert alert--neutral">
<i data-lucide="info"></i>
<div>A neutral alert with <a href="#" class="alert__link">a primary link</a>.</div>
</div>
<div class="alert alert--info">
<i data-lucide="info"></i>
<div>An info alert with <a href="#" class="alert__link">an info-colored link</a>.</div>
</div>
</div>Customization
Eight variables retune .alert without touching component CSS. Override on .alert itself, on a parent scope, or on :root. The cascade scopes the change.
| Variable | Default | Use |
|---|---|---|
--alert-radius |
var(--st-radius) | Corner radius (per-component override via --st-alert-radius) |
--alert-padding-y |
calc(0.625rem * var(--st-density)) | Vertical padding; doubles when .alert__description is present |
--alert-padding-x |
calc(1rem * var(--st-density)) | Horizontal padding |
--alert-bg |
transparent | Background; --neutral sets --st-surface, intents set a 7% tint of the intent color |
--alert-border-color |
transparent | Border color; --neutral sets --st-border, intents set a 40% tint of the intent color |
--alert-color |
var(--st-foreground) | Body text color |
--alert-icon-color |
var(--st-muted-foreground) | Leading icon color; intents flip this to the intent color |
--alert-link-color |
var(--st-primary) | .alert__link color; intents flip this to the intent color so the link stays readable |
A bare .alert stays transparent because --alert-bg and --alert-border-color default to transparent. The tone modifier provides the visible chrome, so an alert without a tone is invisible by design.