{
  "name": "Banner",
  "source": "src/components/Banner.tsx",
  "propsType": "BannerProps",
  "description": "Banner — a notice about the whole product, across the top of it:\nmaintenance tonight, a trial ending, the workspace in read-only mode.\n\nAN ALERT THAT BELONGS TO THE PAGE, NOT TO A PART OF IT. It is Alert with\n`layout=\"banner\"` — the same intents, roles, icons, colours and one-line\nlayout — and adds what a notice about the whole page needs. Put it in\nthe app shell, above the Header and outside <main>, so it persists across\nroutes: a live region is announced when it is inserted, and a banner that\nremounts with every page would be announced on every page.\n\nDISMISSED MEANS DISMISSED. With `dismissKey` the dismissal is remembered in\nthis browser, so a user who has read the maintenance notice is not shown it\non every page and every visit. A banner that must stay — the workspace is\nread-only, deletion is scheduled — has no key and no `onDismiss`, and no\ndismiss button.\n\nFOCUS GOES FORWARD. Dismissing removes the button that had focus; focus\nmoves to the next thing after the banner rather than falling back to the\ntop of the document.",
  "import": "import { Banner } from 'ionbase-ui';",
  "status": "stable",
  "summary": "A notice about the whole product, across the top of it — maintenance tonight, a trial ending, the workspace read-only or scheduled for deletion. Alert's banner layout on one line, in the app shell; a dismissal is remembered with `dismissKey`.",
  "useWhen": [
    "the notice is about the product or the account, not about what is on this page — maintenance, an outage, a plan limit, read-only mode, a pending deletion",
    "it must be seen on every page until it is dealt with or dismissed"
  ],
  "useInstead": [
    {
      "when": "the notice is about one part of the page — a form, a panel, a table",
      "use": "Alert",
      "why": "an Alert sits with what it is about; a banner about a form reads as a problem with the whole product"
    },
    {
      "when": "a result the user just caused — saved, sent, deleted",
      "use": "Toast",
      "why": "it comes and goes by itself; a banner stays until dealt with"
    }
  ],
  "composition": {
    "order": [
      "Banner",
      "Header"
    ],
    "note": "In the app shell, above the Header and outside <main>, so it persists across routes and is announced once. Several stack, the most severe first. `actions` holds one Link or small Button, beside the message.",
    "example": "<Banner intent=\"information\" title=\"Maintenance on Sunday\" dismissKey=\"maintenance-2026-10-04\" actions={<Link href=\"/status\">Status page</Link>}>From 02:00 to 03:00 UTC.</Banner>"
  },
  "variants": {
    "intent": {
      "information": {
        "use": "the default — maintenance, a new feature, a plan change"
      },
      "warning": {
        "use": "something the user should act on — a trial ending, a deletion scheduled, read-only mode"
      },
      "error": {
        "use": "the product is not working — an outage, a failed payment that has stopped runs"
      },
      "success": {
        "use": "rarely — a state that has just been restored, shown once"
      },
      "neutral": {
        "use": "a notice with no judgement attached"
      },
      "primary": {
        "use": "rarely — a brand announcement"
      }
    },
    "emphasis": {
      "subtle": {
        "use": "the default"
      },
      "solid": {
        "use": "one banner that must not be missed, such as an outage"
      }
    }
  },
  "a11y": {
    "requires": [
      "a message that says what is happening and what it means for the user, in words",
      "`dismissLabel` translated"
    ],
    "guarantees": [
      "the role follows the intent, as Alert's does: `alert` for warning and error, `status` for the rest — announced when it is inserted, not on every page, because it lives in the shell",
      "with `dismissKey`, dismissed stays dismissed in this browser — on every page and the next visit — and a remembered dismissal is never painted",
      "without `dismissKey` or `onDismiss` there is no dismiss button: a banner that must stay cannot be dismissed",
      "dismissing moves focus to the next focusable element after the banner, not to the top of the document",
      "blocked storage — a private window — leaves it showing and dismissible for the page",
      "title, message and action share one line where there is room, and wrap on a phone without running past the edge; it is not sticky"
    ],
    "notes": [
      "change the key when the notice changes — `maintenance-2026-10-04`, not `maintenance` — or a user who dismissed last month's will never see this month's",
      "more than two banners at once is a sign some of them belong elsewhere"
    ]
  },
  "antiPatterns": [
    {
      "dont": "a Banner inside each page's content",
      "do": "one place in the app shell",
      "why": "remounted on every route, a live region is announced on every route, and it moves with each page's layout"
    },
    {
      "dont": "<Banner dismissKey=\"deletion\"> for a scheduled deletion",
      "do": "no dismissKey and no onDismiss",
      "why": "a notice the user must not forget cannot be one they can make go away"
    },
    {
      "dont": "a sticky banner",
      "do": "a banner that scrolls away with the page",
      "why": "stuck to the top of a phone, it takes a block of every screen for as long as it is there"
    }
  ],
  "stylesheet": null,
  "tokens": [],
  "props": {
    "dismissKey": {
      "type": "string | undefined",
      "required": false,
      "origin": "own",
      "description": "Makes the banner dismissible and remembers the dismissal in this\nbrowser, under this key, so it does not come back on the next page or\nthe next visit. Change the key when the notice changes —\n`maintenance-2026-10-04`, not `maintenance`."
    },
    "onDismiss": {
      "type": "(() => void) | undefined",
      "required": false,
      "origin": "own",
      "description": "Makes it dismissible, and is told when it is dismissed. Without\n`dismissKey`, the dismissal lasts only until the banner is mounted again."
    },
    "title": {
      "type": "React.ReactNode",
      "required": false,
      "origin": "own",
      "description": "Optional heading above the message."
    },
    "children": {
      "type": "React.ReactNode",
      "required": false,
      "origin": "own",
      "description": "The message."
    },
    "intent": {
      "type": "AlertIntent | undefined",
      "required": false,
      "origin": "own",
      "description": "Matches the Figma `Intent` variant. Same vocabulary as `Badge`.",
      "values": [
        "neutral",
        "primary",
        "success",
        "warning",
        "error",
        "information"
      ]
    },
    "emphasis": {
      "type": "AlertEmphasis | undefined",
      "required": false,
      "origin": "own",
      "description": "Matches the Figma `Emphasis` variant.",
      "values": [
        "subtle",
        "solid"
      ]
    },
    "hideIcon": {
      "type": "boolean | undefined",
      "required": false,
      "origin": "own",
      "description": "Hide the leading icon. Shown by default."
    },
    "icon": {
      "type": "React.ReactNode",
      "required": false,
      "origin": "own",
      "description": "Replace the intent's glyph."
    },
    "actions": {
      "type": "React.ReactNode",
      "required": false,
      "origin": "own",
      "description": "Action buttons, rendered under the message."
    },
    "dismissLabel": {
      "type": "string | undefined",
      "required": false,
      "origin": "own",
      "description": "Accessible name for the dismiss button."
    }
  },
  "propCounts": {
    "own": 10,
    "aria": 0,
    "dom": 276,
    "other": 0
  }
}
