<!-- GENERATED by scripts/build-llms.mjs from llms/overlays.md — do not edit this file. -->

# `lr-alert`

- **Import** `import '@aceshooting/lyra-ui/components/lr-alert.js';` (stable tag alias; registers the tag)
- **Class** `LyraAlert`, also available unregistered from `@aceshooting/lyra-ui/components/overlays/alert/alert.class.js`
- **Family** `components/overlays/` — see `llms/index.md` for its siblings
- **Status** `stable` since `8.0.0` — see the maturity and deprecation policy in `llms/shared.md`
- **Release history** [CHANGELOG.md](../../CHANGELOG.md); family-wide breaking-change summaries: [llms-full.txt](../../llms-full.txt)
- **Deprecations** none
- **Optional peers** none
- **Themeable via** 5 parts, 2 custom properties — see this component's own `@csspart`/`@cssprop` list below
- **Library-wide behavior** (events, form association, `locale`/`strings`, tokens, TS types): `llms/shared.md`

---

## `lr-alert`

A closed-by-default alert that carries the pinned Shoelace alert surface under the `lr-` prefix,
plus one additive Lyra property (`size`) that is inert until you set it.
Use `lr-callout` for Lyra/Web Awesome's always-open inline callout contract; use `lr-alert`
when migrated markup relies on `open`, timed dismissal, countdown, or identity-preserving
`toast()` behavior.

**Properties:**

- `open: boolean = false` (reflected) — controls visibility. Initial `open` markup establishes
  state without a transition event; later property or attribute changes run the full lifecycle
  below.
- `closable: boolean = false` (reflected) — renders a localized close action.
- `size?: LyraSize` (reflected, unset by default) — density tier on the library's one size ladder:
  `'2xs'|'xs'|'s'|'m'|'l'|'xl'`, or the Web Awesome / Shoelace spellings `'small'|'medium'|'large'`,
  which are accepted as authored rather than rewritten to the short form. This is the one Lyra
  addition on top of the pinned Shoelace surface, and it is opt-in for that reason: unset, the panel
  keeps the padding it always had and the text size it inherits, so migrated markup renders
  unchanged. A tier scales the panel padding and text together and takes `lr-callout`'s values for
  both, so a tiered alert and a tiered callout of the same size line up in one column. Their
  **untiered** states are not interchangeable, deliberately: with no `size` this panel keeps a fixed
  gutter and inherits the ambient text size (its exact pre-ladder rendering), while an untiered
  `lr-callout` reads the ambient form-control slots and falls back to the shared `m` padding and
  `--lr-font-size-m`. Pinning a default tier here would resize every alert that shipped before this
  property existed. Two things deliberately do not vary by tier, also matching `lr-callout`: the gap
  separating icon, message and close action (it separates three boxes rather than setting density)
  and the leading icon glyph size (a status affordance bounded by the shared tappable-target token).
  The close action also keeps the shared tappable-target floor at every tier — a WCAG 2.5.8 minimum
  rather than a density knob — and its optical pull-out toward the panel edge is clamped to the
  tier's own gutter, so the two smallest tiers cannot push it through the panel's clipped border. An
  unsupported value normalizes to the omitted state and removes the attribute.
- `variant: 'primary' | 'success' | 'neutral' | 'warning' | 'danger' = 'primary'` (reflected) —
  `primary` resolves through Lyra's shared brand semantic tokens. Unsupported attributes and
  untyped property writes normalize to reflected `primary`.
- `duration: number = Infinity` — milliseconds before automatic dismissal. `Infinity` stays open;
  hover or focus pauses the timer, and leaving interaction restarts the full duration.
- `countdown: 'rtl' | 'ltr' | undefined` (reflected, unset by default) — adds a decorative visual
  bar that empties in the requested physical direction. Its motion is removed under
  `prefers-reduced-motion: reduce`. Unsupported attributes and untyped property writes normalize
  to the omitted state and remove the attribute.
- `role: string | null = 'alert'` (reflected) — the light-DOM semantic owner. The default is a
  reactive initial value, so SSR/no-JS output serializes it before `connectedCallback`; an authored
  alternate role such as `status` remains authoritative.

**Methods:** `show(): Promise<void>` and `hide(): Promise<void>` resolve after their respective
after-event. `toast(): Promise<void>` moves the same alert instance into Lyra's singleton logical
top-end toast region, shows it, and resolves after it hides and is removed. Keep the reference to
reuse the same identity with another `toast()` call. An alert adopted into another same-origin
document uses that document's toast region, timers, motion preference, and focus realm. If external
DOM reconciliation removes a toast without hiding it, the pending promise settles after that
disconnect proves lasting (a synchronous move into the toast region does not count), stale
listeners are released, and a later `toast()` starts a fresh lifecycle.
The region admits three active alerts and twenty hidden/inert queued alerts in FIFO order. An
already-open alert also becomes explicitly hidden and inert while queued; promotion preserves that
accepted state without replaying `lr-show`. If focus was inside that surface, queue admission repairs
it to an available adjacent control without overriding a newer external focus destination. An initial
`lr-show` veto removes and settles that toast attempt; a later `toast()` uses a fresh promise and can
retry. Re-entering `show()` or the same `open` request during the before-event coalesces, so an outer
veto cannot be bypassed by a nested request.
In an adopted document without an upgraded bounded toast controller, `toast()` fails closed by
removing the unavailable request and settling its unchanged `Promise<void>` rather than appending to
an unbounded fallback element. Region ownership is reasserted when an alert moves between stacks;
stale observations from its previous stack cannot change its active/queued state. A lasting region
disconnect discards managed work, so reconnecting that old region cannot resurrect an already-settled
alert toast.

**Events:** `lr-show`, `lr-after-show`, `lr-hide`, and `lr-after-hide` all bubble, compose, carry no
detail. `lr-show` and `lr-hide` are cancelable veto points; their `lr-after-*` counterparts are
noncancelable. A transition interrupted by the opposite state does not emit the stale after-event.
When an accepted hide removes the focused close action, focus moves to the nearest available
composed action. A veto keeps focus in place, and a listener-selected external destination wins.
An accepted show/hide interrupted by a same-task move resumes and emits exactly one matching
after-event before its method resolves. A lasting disconnect settles the method without emitting on
the detached node; reconnecting the same inline alert later resumes the pending terminal lifecycle
once. Toast-owned work instead settles and is discarded when its region disconnect proves lasting.

**Slots:** default message content; `icon` for an optional decorative leading icon whose flattened
subtree remains visible but is inert and aria-hidden.

**CSS parts:** `base`, `icon`, `message`, and `close-button` / `close-button__base` on the same
native close button. The pinned surface exposes no custom states, form association, native-event
relays, or delegated native methods.

**Themeable custom properties:** the close button's two state hooks are
`--lr-alert-close-hover-bg` (its `:hover` surface; default `color-mix(in oklab, transparent,
var(--lr-color-mix-partner) var(--lr-color-mix-hover))`) and `--lr-alert-close-active-bg` (its
`:active` surface, scoped independently from the hover property; default `color-mix(in oklab,
transparent, var(--lr-color-mix-partner) var(--lr-color-mix-active))`). Each is an inline fallback
at the relevant state, so setting one on the alert or an ancestor rethemes only that close-button
state.

By default the light-DOM `<lr-alert>` host owns `role="alert"`, so initially-open/static alerts and
alerts shown later expose one assertive, content-derived semantic surface without duplicating it in
a shadow or shared live region. The role is present in server output; an explicit authored role is
preserved. The optional icon wrapper remains visible, but its flattened subtree is inert
and `aria-hidden`; the close action remains independently accessible through Lyra's localized
`close` string. Layout uses logical properties, wraps unbroken content at 320px, and the toast path
reuses the existing Lyra toast layer instead of creating a second placement system.

```html
<lr-alert
  id="session-alert"
  closable
  duration="10000"
  countdown="rtl"
  variant="warning"
>
  <svg slot="icon" aria-hidden="true"><!-- warning icon --></svg>
  Your session will expire soon.
</lr-alert>
<button type="button" onclick="document.querySelector('#session-alert').show()">
  Show alert
</button>

<script type="module">
  import "@aceshooting/lyra-ui/components/overlays/alert/alert.js";

  const alert = document.querySelector("#session-alert");
  alert.addEventListener("lr-after-hide", () => console.log("Alert is hidden"));
</script>
```
