Skip to content

Components · Status and feedback

CalloutBanner

Page- or section-level banner: trials, maintenance, billing, failed syncs and narrowed scopes.

@rookcom/monarch-reactComponent

Page banner with an action

Your trial ends in 3 days

Add a payment method to keep your workspace and its data.

Usage examples

Tones

Scope notice

Purpose

A message about the account, the product or the whole view, shown above the content it affects. It can carry actions, be dismissed (the product decides whether that sticks) and be a landmark.

Use when

  • Account or workspace state that affects everything: a trial ending, a failed payment, a plan limit.
  • Planned or ongoing maintenance, or a degraded service.
  • A section-level problem with a fix, such as a failed sync with Retry.
  • The view is narrowed to a Space, team or filter and the user should be able to clear it (variant="scope").

Avoid when

  • Confirming an action that just happened: use Toast.
  • A short note attached to one field, row or card: use InlineNotice.
  • A message about one section with a title and a paragraph that never needs dismissing: Alert is enough.
  • The user must decide before continuing: use Dialog.

Design principles

  • One banner per placement: stack at most one page banner above the app and one section banner above a view.
  • Lead with the consequence ("Your trial ends in 3 days"), then what to do, then the action.
  • Silent by default. Set live only when the banner appears because of something that just happened.
  • Dismissal persistence is the product’s: onDismiss fires, Monarch stores nothing, and defaultOpen={false} hides a banner the user already closed.
  • Tone carries meaning, never colour alone: every tone has its own icon, and the text says what happened.

API reference

import { CalloutBanner } from '@rookcom/monarch-react';
ExportKindRenderingRoot class
CalloutBannercomponentclient.mn-callout-banner

Forwards its ref to the root element (<div>, <section> or <aside> depending on landmark).

All native attributes pass through to the root, including aria-label for a landmark with no title.

Renders nothing while closed.

Generated from the TypeScript declarations of packages/react/src/components/feedback/callout-banner.

Properties

CalloutBanner

A page- or section-level message about the account, the product or the current view: trials, maintenance windows, billing problems, a failed sync, a narrowed scope. Optionally dismissible, with an action slot and a landmark role.

PropTypeDescription
actionPlacement"inline" | "end"`end` puts actions on the trailing edge (below the text on narrow screens); `inline` puts them right after the text, like a sentence that ends in a link. Default `end`.
actionsReactNodeButtons or links, for example "Upgrade" or "Retry".
childrenReactNode
classNamestring
defaultOpenbooleanInitial visibility when uncontrolled. Default true.
dismissiblebooleanShows a close button. Implied by `onDismiss`.
dismissLabelstringAccessible name of the close button. Default "Dismiss".
iconReactNodeReplaces the tone icon. Pass `null` for none.
idstring
landmark"none" | "complementary" | "region"Makes the banner a landmark, so screen-reader users can jump to it: `region` (`<section>`) or `complementary` (`<aside>`). Named by `title`, or by `aria-label` when there is no title. Default `none` (`<div>`).
live"polite" | "assertive"Announce the banner's text when it appears: `polite` (role="status") or `assertive` (role="alert", only for errors that block progress). Leave unset for a banner that is present when the page loads.
onDismiss(() => void)Called when the user dismisses the banner (and shows the close button). Store "don't show again" here: Monarch keeps nothing.
openbooleanControlled visibility. Leave unset to let the banner hide itself on dismiss.
placement"section" | "page"`page`: a full-width strip across the top of the app or page (trial, maintenance, billing), with no rounded corners. `section`: a rounded callout inside the content. Default `section`.
titleReactNodeBold first line.
toneCalloutBannerToneColour and default icon. `accent` uses the product accent, for trials, upgrades and announcements. Default `info`.
variant"callout" | "scope"`scope`: a compact, neutral one-line notice that the view is narrowed ("Showing tickets in Support"), usually with an action that clears it. Default `callout`.

Variants

PropValuesDescription
tone'neutral''info''accent''success''warning''danger'Colours and default icon. accent follows the product accent, for trials and announcements. Default info. Exposed as data-tone.
placement'section''page'section: a rounded callout inside the content. page: a full-width strip with only a bottom border, for the top of the app. Default section. Exposed as data-placement.
variant'callout''scope'scope: a compact one-line "you are looking at a subset" notice with no icon by default. Default callout. Exposed as data-variant.
actionPlacement'end''inline'end puts actions on the trailing edge (below the text on narrow screens); inline right after the text. Default end. Exposed as data-action-placement.
landmark'none''region''complementary'Root element and landmark role: <div>, <section> (region) or <aside> (complementary). Default none.

States

StateExposed asBehaviour
Open–Rendered. The default.
Dismissed–Uncontrolled: hidden after the close button is pressed. Controlled: hidden when open becomes false.
Liverole="status" | role="alert" (on the text)Announced when it appears; only when live is set.

Interaction behaviour

  • The close button appears when dismissible or onDismiss is set; pressing it calls onDismiss and, when uncontrolled, hides the banner.
  • With open, the banner stays until the parent sets open={false}, for example after saving the dismissal.
  • If focus was on the close button, it moves to the next focusable element after the banner (or the previous one), never to the page body.
  • Actions are ordinary buttons or links passed in actions.

Keyboard support

KeysAction
TabMoves through the actions, then the close button.
Enter / SpaceActivates the focused action or dismisses the banner.

The banner itself never takes focus when it appears.

Accessibility

Role
none by default; region (<section>) or complementary (<aside>) with landmark
Accessible name
A landmark is named by title (aria-labelledby) or by aria-label.
  • The live role (status or alert) is on the text, not the root, so a landmark keeps its own role and the announcement is only the message.
  • The tone icon is aria-hidden; the title and body carry the meaning.
  • The close button is an IconButton labelled dismissLabel (default "Dismiss").
  • Text and icon colours come from tokens with contrast guaranteed in every theme: title and body on the tinted background, icons in the tone’s strong colour.

Responsive behaviour

  • Below 40rem, trailing actions wrap under the text, aligned with it.
  • The title and body wrap; nothing is truncated. Works down to 320px.
  • placement="page" uses the layout gutter (--mn-layout-gutter) so it lines up with page content.

Theme support

  • Each tone uses its intent subtle, strong and border tokens; accent uses the product accent, so each Rook product gets its own colour.
  • Light, dark and high-contrast themes apply automatically.
  • No animation, so reduced motion needs nothing.

Do and don't

Do

  • Store the dismissal in onDismiss and pass defaultOpen={false} (or open) next time.
  • Give a page banner one clear action; link to details rather than packing in paragraphs.
  • Use landmark="region" for banners people may want to return to, such as maintenance notices.

Don't

  • Do not stack several page banners; show the most urgent one.
  • Do not use live="assertive" for promotions or reminders.
  • Do not make a billing or security problem dismissible if it still blocks the user.
  • Alert: Section message with title and body that is never dismissed.
  • InlineNotice: One line attached to a field, row or card.
  • Toast: Transient confirmation of an action.
  • Button: Actions and the close IconButton.

Dependencies

KindDepends on
npm packagesreact
Monarch componentsButton

Intent subtle, strong and border tokens; --mn-layout-gutter for page placement.

Testing coverage

  • Renders title, body, decorative icon and actions with tone, placement and variant attributes; axe clean.
  • Forwards its ref and native attributes.
  • landmark="region" and "complementary" render named <section> / <aside> landmarks; axe clean.
  • A landmark without a title is named by aria-label.
  • The live role sits on the text inside a landmark (alert / status).
  • Dismisses uncontrolled, calls onDismiss and moves focus to the next control, or the previous one.
  • Controlled open keeps it until the parent closes it; defaultOpen={false} renders nothing.
  • Custom dismiss label; scope variant with inline action and no default icon; icon replace and removal.
  • Renders on the server.
CheckCovered
Axe in jsdomYes
Server renderingYes
Browser suitesVisual baselines: /__gallery; Cross-browser axe: /components/callout-banner

Tests: packages/react/src/components/feedback/callout-banner