Banner
<Banner> is a page- or region-top sentiment ribbon. Use for KPI sentiment, kill-switch warnings, compliance pre-flight states, beta notices — anything that applies to the whole surface rather than to one form field or row.
When to use
- Page-top warning that applies to the whole surface (“Kill-switch armed”, “Beta integration”).
- Region-top sentiment summary (“Sentiment up 12% MoM”).
- Compliance pre-flight states (“Pending legal review”).
Don’t use Banner for: per-field validation (FormError, FormMessage), transient feedback (Sonner), or inline guidance with a CTA inside body content (use Alert).
Variants
The variant chooses the icon, the border tint, and the live-region role.
Sentiment up 12% MoM
Last 30 days vs prior 30. Driven by Q3 campaign close-rate.
Pending legal review
This workflow is paused until compliance pre-flight passes.
Kill-switch armed
Outbound calls suspended for this campaign until manual unlock.
Beta integration
Behavior may change without notice.
<Banner variant="success" title="Sentiment up 12% MoM" description="…" /><Banner variant="warning" title="Pending legal review" description="…" /><Banner variant="destructive" title="Kill-switch armed" description="…" action={<Button size="sm" variant="outline">Unlock</Button>} /><Banner variant="muted" title="Beta integration" description="…" />| Variant | Live-region role | Use |
|---|---|---|
success | status (polite) | Positive sentiment summary, completion. |
warning | alert (assertive) | Pending state, soft warning. The system uses muted-foreground (no amber) per the foundations rule. |
destructive | alert (assertive) | Kill-switch, blocked state, error condition. |
muted | status (polite) | Neutral information, beta notice. |
Dismissible
Banner doesn’t unmount itself — pass dismissible and own the open state in the consumer.
Saved.
Your changes were applied.
const [open, setOpen] = useState(true);
{open && ( <Banner variant="success" title="Saved." description="Your changes were applied." dismissible onDismiss={() => setOpen(false)} />)}API
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "success" | "warning" | "destructive" | "muted" | "muted" | Drives icon, border tint, live-region role. |
title * | ReactNode | — | Headline. One short sentence. |
description | ReactNode | — | Optional second line. |
action | ReactNode | — | Trailing actions (Buttons). Right-aligned. |
icon | ReactNode | — | Override the default per-variant icon. |
dismissible | boolean | false | Show the close X. Pair with onDismiss. |
onDismiss | () => void | — | Called on dismiss click. Component does NOT unmount itself. |
className | string | — | Forwarded. |
Design guidelines
✓ Do
- Use Banner for surface-level state. If it applies to one field, that's FormError. If it's transient, that's Sonner.
- Pair destructive variant with an action (Unlock, Resolve, …) when the user can act.
- Keep the title short — one noun phrase. The description carries the explanation.
✗ Don't
- Use destructive variant for a non-error state to "draw attention". The system has only one red.
- Stack multiple banners. If you have two messages for the same surface, the second is probably an Alert inside the page body.
- Hide an error inside a dismissible banner — users will dismiss it.
Accessibility
successandmuteduserole="status"(polite live region).warninganddestructiveuserole="alert"(assertive — announces immediately).- The variant icon is
aria-hidden— meaning is carried by the title + description. - Dismiss is a real
<button aria-label="Dismiss">, keyboard reachable.