# Toast

Announce transient status from an explicit toaster. (Custom element.)

Reference: https://timeless.build/docs/components/toast/

## Markup

```html
<ui-toaster role="region" aria-label="Notifications" placement="bottom-end" stack="overlap">
  <ui-toast role="status">
    <div data-ui-part="content">
      <h2 data-ui-part="title">Preview ready</h2>
      <p data-ui-part="description">The static example finished building.</p>
    </div>
    <button data-ui-part="close" type="button" aria-label="Dismiss notification">
      <svg aria-hidden="true" focusable="false" viewBox="0 0 16 16">
      <path d="m4.5 4.5 7 7m0-7-7 7" fill="none" stroke="currentColor" stroke-linecap="round" stroke-width="1"/>
    </svg>
    </button>
  </ui-toast>
</ui-toaster>
```

## Install

```js
import '@timelessui/components/css/tokens.css'
import '@timelessui/components/css/core/toast.css'
import '@timelessui/components/css/themes/atmosphere/tokens.css'
import '@timelessui/components/css/themes/atmosphere/toast.css'
import '@timelessui/components/register/ui-toaster'
import '@timelessui/components/register/ui-toast'
```

A `register/` import is a side effect: it defines the element as the module evaluates, so it
has to run in code the browser loads. To register explicitly instead — to control the timing,
or to define into another window — call the function from the matching `define/` entry point,
which registers nothing on its own:

```js
import { defineToasterElement } from '@timelessui/components/define/ui-toaster'
defineToasterElement()
import { defineToastElement } from '@timelessui/components/define/ui-toast'
defineToastElement()
```

## Anatomy

Parts are authored in your own markup and identified by the selector below. Required parts
must be present for the component to work. Private `data-ui-internal-*` hooks are written by
the runtime and must never be authored.

**<ui-toast>**

| Part | Required | Selector | Purpose |
| --- | --- | --- | --- |
| `content` | No | `[data-ui-part~='content']` | Wrapper for the title and description. |
| `title` | No | `[data-ui-part~='title']` | Short summary line. |
| `description` | No | `[data-ui-part~='description']` | Supporting detail. |
| `close` | No | `[data-ui-part~='close']` | Dismiss button. Give it an accessible name. |

## Attributes

Every value below is implemented by the stylesheets this component ships. Boolean attributes
are presence-based: author the attribute with no value, or omit it.

**<ui-toaster>**

| Attribute | Values | Default | Description |
| --- | --- | --- | --- |
| `placement` | `top-start` · `top-center` · `top-end` · `bottom-start` · `bottom-center` · `bottom-end` | `bottom-end` | Corner or edge of the viewport the toasts stack against. |
| `stack` | `overlap` · `list` | `overlap` | Whether queued toasts overlap into a deck (`overlap`) or lay out as a full list (`list`). |

**<ui-toast>**

| Attribute | Values | Default | Description |
| --- | --- | --- | --- |
| `duration` | any `number` | `5000` | Milliseconds before the toast dismisses itself. `0` keeps it open until dismissed. |
| `persistent` | presence | absent | Present to disable auto-dismiss regardless of `duration`. |

## Element API

Attributes above are the authoring surface. These are the DOM properties and events the
registered element adds once it upgrades.

### `<ui-toaster>`

| Property | Type | Notes |
| --- | --- | --- |
| `placement` | `'top-start' | 'top-center' | 'top-end' | 'bottom-start' | 'bottom-center' | 'bottom-end'` | Reflects the `placement` attribute |
| `stack` | `'overlap' | 'list'` | Reflects the `stack` attribute |

This element dispatches no component events.

### `<ui-toast>`

| Property | Type | Notes |
| --- | --- | --- |
| `duration` | `string` | Reflects the `duration` attribute |
| `persistent` | `boolean` | Reflects the `persistent` attribute |

| Event | Detail | Description |
| --- | --- | --- |
| `ui-dismiss` | `CustomEvent<ToastDismissDetail>` | Dispatched when the toast is dismissed. The detail names the reason: a timeout, the close control, or the imperative API. |

## Styling

Root identity: `ui-toaster`, `ui-toast`.
Required stylesheets: `tokens.css`, `core/toast.css`, `themes/atmosphere/tokens.css`, `themes/atmosphere/toast.css`.

Set these custom properties to restyle the component:

| Custom property | Controls |
| --- | --- |
| `--ui-toaster-gap` | Gap between toasts in `list` mode. |
| `--ui-toaster-overlap` | Offset between stacked toasts in `overlap` mode. |

Design tokens this component reads (13), global and set at the theme level: `--ui-bg-control`, `--ui-bg-surface`, `--ui-fg`, `--ui-fg-muted`, `--ui-focus`, `--ui-line`, `--ui-radius-lg`, `--ui-radius-md`, `--ui-shadow-floating`, `--ui-space-1`, `--ui-space-3`, `--ui-space-4`, `--ui-space-5`.

## Accessibility

Keep the native elements, roles, and relationships shown in the markup. Timeless adds only the
state and keyboard coordination the platform does not already provide, and it never supplies
your accessible names — those depend on your content.

**<ui-toaster>**

Follows the [Alert pattern](https://www.w3.org/WAI/ARIA/apg/patterns/alert/) from the ARIA Authoring Practices Guide.

The toaster is the live region, and it is yours to name — author `role="region"` with an `aria-label`, or `role="status"` when the whole surface should announce. Timeless supplies both as a default and neither as a replacement for your own. Nothing here traps focus or steals it: a toast appears without moving the user, and is reached with Tab like anything else. Choose the role by urgency, not by appearance: `role="status"` on a toast is polite and waits its turn, `role="alert"` interrupts and should be rare.

**<ui-toast>**

Follows the [Alert pattern](https://www.w3.org/WAI/ARIA/apg/patterns/alert/) from the ARIA Authoring Practices Guide.

Give the toast the role its urgency deserves — `role="status"` for the ordinary case, `role="alert"` only when it must interrupt — and give the close control an accessible name. SC 2.2.1 is the criterion to hold in mind: `duration` defaults to 5000ms, and the timer stops while the toast is hovered or contains focus, so nobody loses the message they are reading or the control they are reaching for. `persistent`, or `duration="0"`, removes the limit outright, which is the right choice for anything the user must act on. Dismissing a toast that holds focus hands focus to a surviving toast, or back to wherever it came from, rather than dropping it on `<body>`.

## Before JavaScript runs

The markup above is complete and usable on its own: native controls submit, labels associate, and authored ARIA is already correct. Registration adds state synchronisation, focus management, and keyboard coordination on top of it.
