# xpl-banner

Banners display a system level or page level message at the top of the screen. The section-banner variant displays important messages inline within a section.

## Usage

### Web component (`<xpl-banner>`)

Bar layout (default) with heading, description, primary action, and dismiss:

```html
<xpl-banner
  appearance="information"
  heading="Your session will expire soon."
  description="Save your work to avoid losing changes."
  action-text="Extend session"
  is-dismissible="true"
></xpl-banner>
```

Section layout with optional secondary action and no leading icon:

```html
<xpl-banner
  appearance="positive"
  is-section="true"
  has-icon="false"
  heading="Changes saved"
  description="Your updates are stored."
  action-text="View details"
  secondary-action-text="Undo"
></xpl-banner>
```

### Plain HTML (BEM classes)

Use the same structure when styling with `banner.css` without the Stencil component. Switch bar vs section with host modifiers (`xpl-banner--section`, `xpl-banner--no-icon`, `xpl-banner--{appearance}`).

## Accessibility

`xpl-banner` uses `role="region"` so the banner is a navigable landmark.

**`aria-label` on the host (never empty):**

| Layout | `aria-label` source |
| ------ | ------------------- |
| Bar (default) | Fixed label from `appearance`: `"Information banner"`, `"Positive banner"`, `"Warning banner"`, or `"Error banner"`. |
| Section | Trimmed `heading` when present; otherwise `"Section banner"`. |

Keyboard: **Tab** moves focus to action buttons and the dismiss control; **Enter** and **Space** activate `xpl-button` actions and the dismiss button. Focus rings use `:focus-visible` (dismiss uses appearance-specific outline tokens in CSS; actions use `xpl-button` focus styles).

- The leading icon wrapper carries `aria-hidden="true"` — the icon is decorative; the message text is the accessible content.
- The dismiss `<xpl-icon>` inside the dismiss button also carries `aria-hidden="true"` so the decorative icon is not announced in addition to the button label.
- The dismiss button `aria-label` is `"Dismiss banner"` in bar layout and `"Dismiss section banner"` when `is-section` is true.

## Token Use

- `information`
  - Background: `--xpl-background-messaging-information`
  - Border: `--xpl-border-accent-information`
  - Icon: `--xpl-icon-default`
  - Main text: `--xpl-text-strong` (with `--xpl-text-default` fallback)
  - Detail text: `--xpl-text-default`
- `warning`
  - Background: `--xpl-background-messaging-warning`
  - Border: `--xpl-border-accent-warning`
  - Icon: `--xpl-icon-default`
  - Main text: `--xpl-text-strong` (with `--xpl-text-default` fallback)
  - Detail text: `--xpl-text-default`
  - Dismiss focus ring: `--xpl-border-accent-warning`
- `positive`
  - Background: `--xpl-background-messaging-positive`
  - Border: `--xpl-border-positive`
  - Icon: `--xpl-icon-default`
  - Main text: `--xpl-text-strong` (with `--xpl-text-default` fallback)
  - Detail text: `--xpl-text-default`
- `error`
  - Background: `--xpl-background-messaging-negative-bold`
  - Border: `--xpl-border-negative`
  - Icon and text: `--xpl-text-inverse-on-dark`
  - Dismiss focus ring: `--xpl-text-inverse-on-dark`
- Dismiss button follows the same icon token as the current appearance.
- `information` dismiss focus ring uses `--xpl-border-accent-information`.

Light and dark mode are handled by Apollo Foundation token definitions. `xpl-banner` does not use component-level `.dark` token overrides.

## Icon Mapping

Each `appearance` value maps to a fixed `xpl-icon` name. When building the component in plain HTML, use the icon from this table:

| `appearance`  | `xpl-icon` name    |
| ------------- | ------------------ |
| `information` | `circle-info`      |
| `warning`     | `triangle-warning` |
| `positive`    | `circle-check`     |
| `error`       | `octagon-warning`  |

## Actions

Use `actionText` and `secondaryActionText` to render up to two `xpl-button` actions in the banner.
Both action buttons always render at `size="xs"` to match compact banner spacing.

The `variant` and `state` attributes on the action buttons depend on both `appearance` and layout:

| Layout    | `appearance`  | `variant`   | `state`     |
| --------- | ------------- | ----------- | ----------- |
| bar       | `information` | `subtle`    | —           |
| bar       | `warning`     | `subtle`    | —           |
| bar       | `positive`    | `subtle`    | —           |
| bar       | `error`       | `primary`   | `warning`   |
| section   | `information` | `subtle`    | —           |
| section   | `warning`     | `subtle`    | —           |
| section   | `positive`    | `subtle`    | `success`   |
| section   | `error`       | `subtle`    | `warning`   |

## Section Layout

Set `is-section` to render the section-banner layout:
- Header row with icon, heading, and optional dismiss
- Description below the header (2-line clamp by default)
- Actions below description

Set `has-icon="false"` to hide the leading icon in the section layout. This applies `xpl-banner--no-icon` on the host, which shifts heading, description, and actions to start in the first grid column instead of the second. In bar layout the icon always renders regardless of `hasIcon`.

Bar and section variants share the same DOM shape. Plain-HTML example (classes only):

```html
<!-- Bar variant -->
<div class="xpl-banner xpl-banner--information">
  <div class="xpl-banner__icon" aria-hidden="true">
    <xpl-icon icon="circle-info" size="24"></xpl-icon>
  </div>
  <div class="xpl-banner__body">
    <p class="xpl-banner__heading">Heading</p>
    <p class="xpl-banner__description">Description text</p>
  </div>
  <div class="xpl-banner__actions">
    <xpl-button size="xs" variant="subtle">Action</xpl-button>
  </div>
  <button class="xpl-banner__dismiss" type="button" aria-label="Dismiss banner">
    <xpl-icon icon="xmark" size="24" aria-hidden="true"></xpl-icon>
  </button>
</div>

<!-- Section variant — add xpl-banner--section; same markup otherwise -->
<div class="xpl-banner xpl-banner--section xpl-banner--information">
  ...
</div>

<!-- Section variant without icon -->
<div class="xpl-banner xpl-banner--section xpl-banner--no-icon xpl-banner--information">
  <!-- omit .xpl-banner__icon -->
  <div class="xpl-banner__body">...</div>
  ...
</div>
```

<!-- Auto Generated Below -->


## Properties

| Property              | Attribute               | Description                                                                                                                                                                                                                                                                | Type                                                  | Default         |
| --------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | --------------- |
| `actionText`          | `action-text`           | Primary action label. When provided, an action button is rendered.                                                                                                                                                                                                         | `string`                                              | `undefined`     |
| `appearance`          | `appearance`            | Controls the visual appearance and semantic meaning of the banner. These values map to messaging background/border token sets in `banner.css`. Banner icons use `--xpl-icon-default`, except `error` which uses inverse icon/text tokens for contrast on dark backgrounds. | `"error" \| "information" \| "positive" \| "warning"` | `'information'` |
| `description`         | `description`           | Optional supporting message shown after the heading. Description text uses `--xpl-text-default`.                                                                                                                                                                           | `string`                                              | `undefined`     |
| `hasIcon`             | `has-icon`              | Whether to render the leading icon in section layout. Ignored in bar layout — bar banners always show the icon.                                                                                                                                                            | `boolean`                                             | `true`          |
| `heading`             | `heading`               | Primary banner message shown with stronger title typography.                                                                                                                                                                                                               | `string`                                              | `undefined`     |
| `isDismissible`       | `is-dismissible`        | Whether to show the trailing dismiss control.                                                                                                                                                                                                                              | `boolean`                                             | `true`          |
| `isSection`           | `is-section`            | Renders the section-style banner layout when true.                                                                                                                                                                                                                         | `boolean`                                             | `false`         |
| `secondaryActionText` | `secondary-action-text` | Secondary action label. When provided, a second action button is rendered.                                                                                                                                                                                                 | `string`                                              | `undefined`     |
| `truncateDesc`        | `truncate-desc`         | When true, `description` is constrained to one line with ellipsis so banner height stays stable.                                                                                                                                                                           | `boolean`                                             | `false`         |


## Events

| Event             | Description                                   | Type                |
| ----------------- | --------------------------------------------- | ------------------- |
| `action`          | Emitted when the primary action is clicked.   | `CustomEvent<void>` |
| `dismiss`         | Emitted when the dismiss button is clicked.   | `CustomEvent<void>` |
| `secondaryAction` | Emitted when the secondary action is clicked. | `CustomEvent<void>` |


## Dependencies

### Depends on

- [xpl-icon](../xpl-icon)
- [xpl-button](../xpl-button)

### Graph
```mermaid
graph TD;
  xpl-banner --> xpl-icon
  xpl-banner --> xpl-button
  xpl-button --> xpl-icon
  style xpl-banner fill:#f9f,stroke:#333,stroke-width:4px
```

----------------------------------------------

*Built with [StencilJS](https://stenciljs.com/)*
