Banner
Communicates a prominent system-level message at the top of the screen, regardless of the user's place in the application.
Usage
import { Banner } from "@opengovsg/oui"<Banner>Your session will expire in 5 minutes.</Banner>import { Banner } from "@opengovsg/oui"export const Example = () => { return <Banner isDismissable>This is a dismissable banner.</Banner>}Alternatively, install the component as local source via the shadcn CLI:
npx shadcn@latest add https://oui.open.gov.sg/r/banner.jsonpnpm dlx shadcn@latest add https://oui.open.gov.sg/r/banner.jsonnpx shadcn@latest add https://oui.open.gov.sg/r/banner.jsonbunx --bun shadcn@latest add https://oui.open.gov.sg/r/banner.jsonBanner communicates a prominent system-level message pinned at the top of the page. It supports an optional dismiss button and variant-based icons. For transient notifications, use Toast instead.
Sizes
Use the size prop to change the size of the banner.
import { Banner } from "@opengovsg/oui"export const Example = () => { return ( <div className="flex flex-1 flex-col gap-4"> <Banner size="sm">Banner (sm)</Banner> <Banner size="md">Banner (md)</Banner> </div> )}Variants
Use the variant prop to change the visual style of the Banner.
import { Banner } from "@opengovsg/oui"export const Example = () => { return ( <div className="flex flex-1 flex-col gap-4"> <Banner variant="info">Banner (info)</Banner> <Banner variant="warning">Banner (warning)</Banner> <Banner variant="error">Banner (error)</Banner> <Banner variant="unstyled">Banner (unstyled)</Banner> </div> )}Custom icon
By default, Banner displays an appropriate icon based on the variant prop. You can override this by providing a custom icon using the startContent prop.
import type { SVGProps } from "react"import { Banner } from "@opengovsg/oui"const UserIcon = ({ ...props }: SVGProps<SVGSVGElement>) => { return ( <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props} > <path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" /> <circle cx="12" cy="7" r="4" /> </svg> )}export const Example = () => { return ( <div className="flex flex-1 flex-col gap-4"> <Banner startContent={<UserIcon />}>A banner with a custom icon</Banner> <Banner variant="warning" startContent="🚀"> Or just use an emoji </Banner> </div> )}Hidden icon
You can hide the icon by setting startContent to null.
import { Banner } from "@opengovsg/oui"export const Example = () => { return ( <Banner variant="error" startContent={null}> This banner has no icon </Banner> )}Visibility
Controlled
You can control the banner visibility using the isExpanded and onExpandedChange props.
import { useState } from "react"import { Banner, Button } from "@opengovsg/oui"export const Example = () => { const [isExpanded, setIsExpanded] = useState(true) return ( <div className="flex flex-1 flex-col gap-4"> {isExpanded ? ( <Banner isExpanded={isExpanded} onExpandedChange={setIsExpanded} isDismissable > Dismiss the banner to hide me! </Banner> ) : ( <Button size="sm" className="w-fit" variant="outline" onPress={() => setIsExpanded(true)} > Show Banner </Button> )} </div> )}Uncontrolled
You can also set the initial visibility using the defaultExpanded prop.
This defaults to true if unset.
Accessibility
- Banner renders as a
<section>element; provide an accessible name viaaria-labeloraria-labelledbywhen the page contains multiple banners. - When
isDismissableistrue, the dismiss button receives an accessible label. Ensure the surrounding context makes clear what is being dismissed. - Color alone is not used to convey meaning; each variant includes an icon to reinforce the message type.
Slots
Slots are named regions of the component you can target with custom Tailwind classes via the classNames prop. Each slot below corresponds to a key on the classNames object.
base: The main banner container element.content: The content wrapper that containsstartContentandchildren.startContentWrapper: The wrapper around thestartContentelement.childrenWrapper: The wrapper around thechildrencontent.dismissButton: The dismiss button element (visible whenisDismissableis true).icon: The icon element within the defaultstartContent(when no customstartContentis provided).
Props
Banner
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | The banner message content |
isExpanded | boolean | - | Whether the banner is visible (controlled) |
defaultExpanded | boolean | true | Whether the banner is visible by default (uncontrolled) |
onExpandedChange | (isExpanded: boolean) => void | - | Called when the banner's expanded state changes |
isDismissable | boolean | - | Whether to render a dismiss button that hides the banner when pressed |
startContent | ReactNode | null | - | Content rendered to the left of the message; defaults to a variant-appropriate icon; pass null to hide the icon |
variant | "info" | "warning" | "error" | "unstyled" | "info" | The visual style and color scheme of the banner |
size | "sm" | "md" | "md" | The size of the banner |
classNames | SlotsToClasses<BannerSlots> | - | Custom Tailwind classes for component slots |
className | string | - | Additional class applied to the base element |