Skip to content

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.

import from "@na/ui/components/Banner" ▶ Open in Storybook packages/ui/src/components/Banner.tsx

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.
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="" />
VariantLive-region roleUse
successstatus (polite)Positive sentiment summary, completion.
warningalert (assertive)Pending state, soft warning. The system uses muted-foreground (no amber) per the foundations rule.
destructivealert (assertive)Kill-switch, blocked state, error condition.
mutedstatus (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

  • success and muted use role="status" (polite live region).
  • warning and destructive use role="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.
  • Alert — Inline persistent message scoped to a region.
  • Sonner — Transient feedback that auto-dismisses.
  • FormError — Form-level root error.

▶ Open Banner stories in Storybook