[//]: # (This file is auto-generated by the docs:generate-skills script, do not edit it manually)

# AnnouncementBanner

Import: `import { AnnouncementBanner } from '@neo4j-ndl/react'`

## Props

### AnnouncementBanner

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `as` | `ElementType<any, keyof IntrinsicElements>` |  |  | An override of the default HTML tag of the root of the component. Can also be another React component. |
| `children` | `ReactNode` |  |  | Content to be shown in the announcement banner. |
| `hasIcon` | `boolean` |  | `false` | Shows a status icon. The icon is based on the value of the `variant` prop |
| `icon` | `ReactNode` |  |  | Decorative icon shown when `hasIcon` is true. Only used for `discovery` and `neutral`; those variants fall back to Sparkles and Bolt. `info`, `warning`, and `danger` always use their status icons. |
| `isCloseable` | `boolean` |  | `false` | If the banner is closeable. Renders an icon button on the right |
| `liveRegion` | `'alert' \| 'status'` |  |  | Announces the header when the banner appears or its header changes. `status` announces politely, while `alert` interrupts the user. Leave this unset for banners that are present during the page's initial render. This is independent of the visual `variant`. |
| `onClose` | `((error?: MouseEvent<HTMLElement, MouseEvent> \| KeyboardEvent<HTMLElement>) => void)` |  |  | Event handler for when the close icon is clicked |
| `ref` | `any` |  |  | A ref to apply to the root element. |
| `variant` | `'danger' \| 'discovery' \| 'info' \| 'neutral' \| 'warning'` |  | `info` | The variant of the announcement banner |

### AnnouncementBanner.Actions

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `children` | `ReactNode` | ✅ |  |  |
| `ref` | `Ref<HTMLDivElement>` |  |  | A ref to apply to the root element. |

### AnnouncementBanner.Header

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `children` | `ReactNode` | ✅ |  |  |
| `ref` | `Ref<HTMLSpanElement>` |  |  | A ref to apply to the root element. |

## Accessibility

## Implementation guidelines

Place `AnnouncementBanner` as the first child of its parent so content below is shifted down by the banner’s height. The banner stays in normal document flow (not sticky or fixed), so it does not overlay content underneath and does not obscure focused content (WCAG 2.2 SC 2.4.11 Focus Not Obscured).

### Content and meaning

- Put the announcement meaning in text. Status icons are decorative (`aria-hidden` on the icon wrapper) and reinforce the `variant` visually; do not rely on color or the icon alone to convey severity (WCAG 2.2 SC 1.4.1 Use of Color). Prefer wording such as “Warning: …” or “Error: …”.
- `info`, `warning`, and `danger` always use the built-in status icons. For `discovery` and `neutral`, pass `icon` to replace Sparkles or Bolt; custom icons stay decorative through the same wrapper.

### Live region semantics

The time at which a banner appears and its urgency are separate concerns:

- `variant` communicates visual meaning and never enables a live region.
- `liveRegion` controls whether a new or updated header is announced (WCAG 2.2 SC 4.1.3 Status Messages).

Use `liveRegion` only when a banner appears or changes after the page is ready and the user may already be interacting with it. Omit it for banners that are part of the initial page or shell render, including important `warning` and `danger` banners. Data that resolves as part of normal initial page loading does not necessarily make a banner a live update.

| `liveRegion` | Behavior | Use when |
| --- | --- | --- |
| `"status"` | Uses `role="status"` (`aria-live="polite"`) | New information is useful but can wait until the screen reader reaches a natural pause. |
| `"alert"` | Uses `role="alert"` (`aria-live="assertive"`) | New information is sufficiently urgent that interrupting the user is justified. |
| omitted | No live region | The banner is present during initial rendering, regardless of its visual severity. |

| Scenario | Recommended semantics |
| --- | --- |
| A deprecation, license, payment, or service warning is present during initial rendering | Omit `liveRegion`; choose an appropriate `variant` |
| A campaign or informational message appears later from polling or an event | `liveRegion="status"` |
| A connection loss, session expiry, or other urgent message appears later | `liveRegion="alert"` |

For reliable announcements across screen readers, the component mounts an empty, visually hidden live region before adding the message after a short delay. Only the text in `AnnouncementBanner.Header` is copied into that region; action and close controls remain available through normal keyboard and screen reader navigation without being duplicated in the announcement. `aria-atomic="true"` is set explicitly for interoperability. Do not add a redundant `aria-live` attribute, because combining it with `role="alert"` can cause duplicate announcements in VoiceOver on iOS.

### Interactive controls

- When `isCloseable` is `true`, the close control is a keyboard-operable button labeled “Close”.
- Action buttons passed into `AnnouncementBanner.Actions` must have accessible names (visible text or `aria-label`).

### Reflow and target size

- Narrow widths are supported without horizontal scrolling (WCAG 2.2 SC 1.4.10 Reflow): below `512px` of banner width the message and actions stack, and long or unbreakable strings (such as URLs) wrap, so the banner reflows down to a 320px viewport / 400% zoom without a horizontal scrollbar.
- Close and action controls meet the 24×24 CSS pixel minimum target size (WCAG 2.2 SC 2.5.8 Target Size Minimum).

## Examples

### Default

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { AnnouncementBanner } from '@neo4j-ndl/react';

const Component = () => {
  return (
    <AnnouncementBanner variant="info" hasIcon={true}>
      <AnnouncementBanner.Header>
        Scheduled maintenance starts tonight at 22:00 UTC.
      </AnnouncementBanner.Header>
    </AnnouncementBanner>
  );
};

export default Component;
```

### Closeable

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { AnnouncementBanner } from '@neo4j-ndl/react';

const Component = () => {
  return (
    <AnnouncementBanner
      isCloseable={true}
      onClose={() => alert('Announcement banner closed')}
    >
      <AnnouncementBanner.Header>
        This announcement can be dismissed.
      </AnnouncementBanner.Header>
    </AnnouncementBanner>
  );
};

export default Component;
```

### Custom Icons

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { AnnouncementBanner } from '@neo4j-ndl/react';
import { GiftIconSolid, RocketLaunchIconSolid } from '@neo4j-ndl/react/icons';

const Component = () => {
  return (
    <div className="n-flex n-flex-col n-gap-token-8 n-w-full">
      <AnnouncementBanner variant="discovery" hasIcon={true}>
        <AnnouncementBanner.Header>
          Discovery with the default Sparkles icon
        </AnnouncementBanner.Header>
      </AnnouncementBanner>
      <AnnouncementBanner
        variant="discovery"
        hasIcon={true}
        icon={<GiftIconSolid />}
      >
        <AnnouncementBanner.Header>
          Discovery with a custom gift icon
        </AnnouncementBanner.Header>
      </AnnouncementBanner>
      <AnnouncementBanner variant="neutral" hasIcon={true}>
        <AnnouncementBanner.Header>
          Neutral with the default Bolt icon
        </AnnouncementBanner.Header>
      </AnnouncementBanner>
      <AnnouncementBanner
        variant="neutral"
        hasIcon={true}
        icon={<RocketLaunchIconSolid />}
      >
        <AnnouncementBanner.Header>
          Neutral with a custom rocket icon
        </AnnouncementBanner.Header>
      </AnnouncementBanner>
    </div>
  );
};

export default Component;
```

### Injected Non Urgent

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import {
  AnnouncementBanner,
  OutlinedButton,
  Typography,
} from '@neo4j-ndl/react';
import { useState } from 'react';

const Component = () => {
  const [isVisible, setIsVisible] = useState(false);

  return (
    <div className="n-flex n-flex-col n-w-full">
      {isVisible && (
        <AnnouncementBanner
          variant="discovery"
          hasIcon={true}
          liveRegion="status"
          isCloseable={true}
          onClose={() => setIsVisible(false)}
        >
          <AnnouncementBanner.Header>
            New Aura features are available for your organization.
          </AnnouncementBanner.Header>
        </AnnouncementBanner>
      )}
      <div className="n-flex n-flex-col n-gap-token-16 n-p-token-24 n-bg-neutral-bg-default">
        <OutlinedButton onClick={() => setIsVisible((visible) => !visible)}>
          {isVisible ? 'Hide announcement' : 'Show announcement'}
        </OutlinedButton>
        <Typography variant="body-medium">
          The page is already loaded. Toggle the announcement in to simulate a
          later campaign or poll. <code>liveRegion=&quot;status&quot;</code>{' '}
          announces politely without interrupting.
        </Typography>
      </div>
    </div>
  );
};

export default Component;
```

### Injected Urgent

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import {
  AnnouncementBanner,
  OutlinedButton,
  Typography,
} from '@neo4j-ndl/react';
import { useState } from 'react';

const Component = () => {
  const [isVisible, setIsVisible] = useState(false);

  return (
    <div className="n-flex n-flex-col n-w-full">
      {isVisible && (
        <AnnouncementBanner variant="danger" hasIcon={true} liveRegion="alert">
          <AnnouncementBanner.Header>
            Error: connection to the database was lost. Reconnecting…
          </AnnouncementBanner.Header>
        </AnnouncementBanner>
      )}
      <div className="n-flex n-flex-col n-gap-token-16 n-p-token-24 n-bg-neutral-bg-default">
        <OutlinedButton onClick={() => setIsVisible((visible) => !visible)}>
          {isVisible ? 'Hide announcement' : 'Show announcement'}
        </OutlinedButton>
        <Typography variant="body-medium">
          The page is already loaded. Toggle the announcement in to simulate a
          connection loss or session expiry.{' '}
          <code>liveRegion=&quot;alert&quot;</code> interrupts the screen reader
          because the message is time-sensitive.
        </Typography>
      </div>
    </div>
  );
};

export default Component;
```

### Present At Page Render

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { AnnouncementBanner, Typography } from '@neo4j-ndl/react';

const Component = () => {
  return (
    <div className="n-flex n-flex-col n-w-full">
      <AnnouncementBanner variant="danger" hasIcon={true}>
        <AnnouncementBanner.Header>
          Warning: your marketplace subscription will be deprecated on September
          19, 2026.
        </AnnouncementBanner.Header>
      </AnnouncementBanner>
      <div className="n-p-token-24 n-bg-neutral-bg-default">
        <Typography variant="body-medium">
          This banner is part of the initial page render, so `liveRegion` is
          omitted. Screen reader users hear it when they reach it in the page,
          not as an interruption.
        </Typography>
      </div>
    </div>
  );
};

export default Component;
```

### Variants

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { AnnouncementBanner } from '@neo4j-ndl/react';

const Component = () => {
  return (
    <div className="n-flex n-flex-col n-gap-token-8 n-w-full">
      <AnnouncementBanner variant="info" hasIcon={true}>
        <AnnouncementBanner.Header>Info announcement</AnnouncementBanner.Header>
      </AnnouncementBanner>
      <AnnouncementBanner variant="warning" hasIcon={true}>
        <AnnouncementBanner.Header>
          Warning announcement
        </AnnouncementBanner.Header>
      </AnnouncementBanner>
      <AnnouncementBanner variant="danger" hasIcon={true}>
        <AnnouncementBanner.Header>
          Danger announcement
        </AnnouncementBanner.Header>
      </AnnouncementBanner>
      <AnnouncementBanner variant="discovery" hasIcon={true}>
        <AnnouncementBanner.Header>
          Discovery announcement
        </AnnouncementBanner.Header>
      </AnnouncementBanner>
      <AnnouncementBanner variant="neutral" hasIcon={true}>
        <AnnouncementBanner.Header>
          Neutral announcement
        </AnnouncementBanner.Header>
      </AnnouncementBanner>
    </div>
  );
};

export default Component;
```

### With Actions

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import {
  AnnouncementBanner,
  OutlinedButton,
  TextButton,
} from '@neo4j-ndl/react';

const Component = () => {
  return (
    <AnnouncementBanner hasIcon={true} variant="warning">
      <AnnouncementBanner.Header>
        Your trial ends in 3 days.
      </AnnouncementBanner.Header>
      <AnnouncementBanner.Actions>
        <OutlinedButton>Upgrade</OutlinedButton>
        <TextButton>Learn more</TextButton>
      </AnnouncementBanner.Actions>
    </AnnouncementBanner>
  );
};

export default Component;
```

### With Page Content

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import {
  AnnouncementBanner,
  OutlinedButton,
  TextButton,
  Typography,
} from '@neo4j-ndl/react';
import { useState } from 'react';

const Component = () => {
  const [isVisible, setIsVisible] = useState(true);

  return (
    <div className="n-flex n-flex-col n-max-w-[768px] n-h-52">
      {isVisible && (
        <AnnouncementBanner
          variant="warning"
          hasIcon={true}
          isCloseable={true}
          onClose={() => setIsVisible(false)}
        >
          <AnnouncementBanner.Header>
            Scheduled maintenance starts tonight at 22:00 UTC.
          </AnnouncementBanner.Header>
          <AnnouncementBanner.Actions>
            <OutlinedButton>Learn more</OutlinedButton>
          </AnnouncementBanner.Actions>
        </AnnouncementBanner>
      )}
      <div className="n-flex n-flex-col n-gap-token-16 n-p-token-24 n-bg-neutral-bg-default n-flex-1 n-min-h-0 n-overflow-y-auto">
        {!isVisible && (
          <div>
            <TextButton onClick={() => setIsVisible(true)}>
              Show announcement again
            </TextButton>
          </div>
        )}
        <Typography variant="title-2">Page title</Typography>
        <OutlinedButton>Can focus</OutlinedButton>
        <Typography variant="body-medium">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque
          tempus, quam non molestie faucibus, orci nibh bibendum urna, ut
          lacinia orci dui a augue. Nullam at risus quam. Fusce pulvinar, metus
          vitae finibus dapibus, nisi ipsum venenatis sapien, at facilisis eros
          massa ac nunc. Aliquam sed odio orci. Vivamus condimentum sit amet
          ipsum bibendum sollicitudin. Etiam eget vehicula urna, et ullamcorper
          libero. Interdum et malesuada fames ac ante ipsum primis in faucibus.
          Proin sodales euismod sem, posuere maximus libero interdum semper.
          Nunc mollis posuere arcu non elementum. Vivamus sed laoreet mauris.
          Etiam fringilla arcu convallis erat vehicula iaculis. Pellentesque
          dictum aliquam cursus.
        </Typography>
        <Typography variant="body-medium">
          Integer vehicula turpis quis risus aliquet congue. Vivamus
          pellentesque nibh ac blandit varius. Fusce placerat lacus ut mauris
          porta, nec facilisis risus pulvinar. Nullam elementum nulla ut laoreet
          imperdiet. Maecenas eget erat erat. Phasellus in turpis placerat,
          imperdiet ante nec, tincidunt nisl. Donec a lacus neque. Nullam
          iaculis ante molestie ultrices semper. Sed non lorem ullamcorper
          ligula elementum convallis. Aenean egestas risus quis tortor cursus
          dapibus. Nulla hendrerit at orci ut scelerisque. Nullam vel bibendum
          tellus. Praesent efficitur ultrices lectus at posuere. Maecenas
          facilisis lacus ac turpis malesuada, sit amet imperdiet ipsum
          condimentum. Donec et nibh eget justo luctus ornare. Maecenas suscipit
          nulla at ullamcorper congue.
        </Typography>
        <Typography variant="body-medium">
          Vestibulum vehicula nibh mi, ultrices condimentum massa venenatis sit
          amet. Pellentesque accumsan mollis ex, id lobortis lacus venenatis id.
          Proin sem dui, mollis id gravida ac, vulputate et lacus. In pharetra
          nunc odio, in fermentum elit dignissim at. Nunc ut justo elit. Proin
          ligula orci, faucibus vitae vehicula nec, faucibus sit amet erat.
          Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque
          pharetra venenatis rutrum. Sed pharetra turpis id arcu maximus,
          interdum rhoncus eros mollis. Donec vitae sapien et odio interdum
          bibendum. Quisque eleifend, sem ut ornare mollis, orci nunc dapibus
          odio, aliquam fringilla augue nulla id magna. Phasellus consectetur,
          velit egestas sodales ultricies, odio nunc facilisis libero, vel
          vehicula nisi quam quis nisl. Proin vel massa libero.
        </Typography>
        <Typography variant="body-medium">
          Sed mollis lacinia tincidunt. Curabitur blandit pellentesque
          consequat. Maecenas mollis pharetra dolor in ornare. Cras vel nibh eu
          nisi venenatis convallis id vel nisl. Curabitur et viverra nisl.
          Phasellus et finibus turpis. Praesent scelerisque vel lectus at
          imperdiet. Curabitur porta egestas magna ullamcorper hendrerit.
        </Typography>
        <Typography variant="body-medium">
          Curabitur hendrerit egestas mi, ut venenatis turpis sagittis nec.
          Proin consectetur, nisi et vehicula placerat, tellus augue luctus
          odio, in commodo mauris urna nec libero. Maecenas eu placerat sapien,
          in aliquam tellus. Sed pharetra nunc id urna iaculis tincidunt. In hac
          habitasse platea dictumst. Donec tincidunt risus vitae congue congue.
          Fusce consequat ut justo ut tristique. Nunc ut urna quis neque
          consequat venenatis. Praesent nec feugiat orci. Vestibulum rutrum dui
          lacus, sit amet vulputate dolor finibus ut. Donec placerat urna eu
          fringilla convallis. Praesent sollicitudin felis at lacus semper, vel
          convallis magna scelerisque.
        </Typography>
      </div>
    </div>
  );
};

export default Component;
```
