Open UI

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.json
pnpm dlx shadcn@latest add https://oui.open.gov.sg/r/banner.json
npx shadcn@latest add https://oui.open.gov.sg/r/banner.json
bunx --bun shadcn@latest add https://oui.open.gov.sg/r/banner.json

Banner 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 via aria-label or aria-labelledby when the page contains multiple banners.
  • When isDismissable is true, 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 contains startContent and children.
  • startContentWrapper: The wrapper around the startContent element.
  • childrenWrapper: The wrapper around the children content.
  • dismissButton: The dismiss button element (visible when isDismissable is true).
  • icon: The icon element within the default startContent (when no custom startContent is provided).

Props

PropTypeDefaultDescription
childrenReactNode-The banner message content
isExpandedboolean-Whether the banner is visible (controlled)
defaultExpandedbooleantrueWhether the banner is visible by default (uncontrolled)
onExpandedChange(isExpanded: boolean) => void-Called when the banner's expanded state changes
isDismissableboolean-Whether to render a dismiss button that hides the banner when pressed
startContentReactNode | 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
classNamesSlotsToClasses<BannerSlots>-Custom Tailwind classes for component slots
classNamestring-Additional class applied to the base element

On this page