Banner
A full-bleed announcement bar for promos, release notes and site-wide notices. Soft tones tint the background, message, icon and action from one semantic token, so the whole bar reads as a single hue.
Installation#
Usage#
import {
Banner,
BannerIcon,
BannerContent,
BannerAction,
} from "@/components/ui/banner"
export function Example() {
return (
<Banner variant="purple" dismissible>
<BannerIcon>
<Megaphone />
</BannerIcon>
<BannerContent>New: cream and moonlight themes just landed.</BannerContent>
<BannerAction href="#">Check it out</BannerAction>
</Banner>
)
}Variants#
Soft tones tint the background from a single semantic token and color the icon, action, and message to match. The message takes a deep, tone-tinted ink (a dark blue, dark purple, ...) on light themes and lifts to a bright tint on dark ones, so it stays readable while the icon and action keep the pure hue. Every tone re-themes across light, dark, cream, and moonlight.
Solid#
Set appearance="solid" for a filled bar. Solid is designed for two theme-stable surfaces: the default inverse bar (flips with the theme) and the brand accent bar. The soft tones stay tinted because the hue tokens shift lightness per theme.
Festive#
Set appearance="festive" for a playful celebration bar: a flat, saturated fill behind white text, the natural home for launches, milestones, and holidays. It ignores the tone variant. Recolor the bar by overriding one CSS variable, --banner-festive-via, with a brand or flag color. Keep it deep and saturated so the white text stays legible across every theme.
Interactive (confetti)#
Add confetti to a festive bar to make it playful: it bursts once on mount and again on every click. The icon pops on the mount burst only, so clicking showers confetti while the icon stays still. The pieces are themed by the --banner-confetti-* tokens, which derive from the festive palette, so they re-tint with it (recolor the bar and the confetti follows). It is decorative and fully honors reduced-motion. Click the bars below.
Ornaments#
Drop a BannerOrnament in to peek a decorative flag, mascot, or emoji in from an edge. It clips to the bar and sits behind the message, tilting away from its side. Below, two Venezuela flags (rounded 16px, not circular) peek from the corners of a flat solid bar, with the confetti tinted to the flag's yellow and red. The flag itself is any element you like, sized and rounded however you want.
Alignment#
The default align="center" centers the message. Switch to align="between" to pin the message left and the action right, the natural home for a Button CTA.
Shape#
shape sets the bar's footprint. The default "bar" runs edge to edge, the classic strip atop a page. "inset" draws the same bar as a rounded card that sits inside the page gutter, above the navbar: place it in a SectionContainer (or any gutter) and it takes that width, its inner row trading the page-width cap for a card interior and a step more height.
Dismissible#
Set dismissible to render a trailing close button. Uncontrolled by default (the banner hides itself); pass open / onOpenChange to control it, and always give a descriptive dismissLabel.
As child action#
Use asChild on BannerAction to render the link styles onto a framework link (e.g. Next.js <Link>) via Radix Slot, keeping client-side navigation.
API reference#
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | default | brand | purple | pink | teal | orange | info | success | warning | destructive | default | Tone of the bar. |
| appearance | soft | solid | festive | soft | Fill style. solid supports default (inverse) and brand; festive is a flat celebration bar themed by the --banner-festive-via var. |
| align | center | between | center | Centered message, or message-left / action-right. |
| shape | bar | inset | bar | Edge-to-edge strip, or a rounded card inside the page gutter. |
| dismissible | boolean | false | Render a trailing close button. |
| confetti | boolean | false | Burst confetti on mount and on click (pairs with festive); honors reduced-motion. |
| open | boolean | - | Controlled visibility. |
| defaultOpen | boolean | true | Uncontrolled initial visibility. |
| onOpenChange | (open: boolean) => void | - | Fires when dismissed. |
| dismissLabel | string | Dismiss | Accessible label for the close button. |
| className | string | - | Merged onto the root, last. |
Parts: Banner, BannerIcon, BannerContent, BannerAction (accepts asChild), and BannerOrnament (decorative edge peek, takes side). Each forwards its native props and merges className last.