A toast answers one question, did the thing I pressed work?, and then gets out of the
way. It is drawn above the page rather than in it, because the reader's attention is on the
control they pressed, not on a corner of the form; it dismisses itself, because the answer
is only interesting for a few seconds.

It is the one component on these pages you do not place. There is a provider that holds the
queue and a hook that fills it, and nothing to render where the message will appear. A
`toast` is also a `status`, never an `alert`: a result is reported, not shouted at.

```tsx demo="feedback/toast-preview"
```

## Usage

```tsx
import { Button, ToastProvider, useToast } from "@asheeui/web";

function App() {
  return (
    <ToastProvider>
      <SaveInvoice />
    </ToastProvider>
  );
}

function SaveInvoice() {
  const toast = useToast();

  return (
    <Button onClick={() => toast.success("Invoice saved")}>Save invoice</Button>
  );
}
```

`toast.success(message, options)` is the shorthand; `toast.error`, `toast.info` and
`toast.warning` are its siblings. `toast(options)` takes the whole message at once, its
`type`, `title`, `message`, `action` and the overrides below, and every one of them returns
the message's id, which is what `removeToast` takes.

## Placing the provider

Put `ToastProvider` once, at the root of the application, above the routes and inside the
application's `AsheeUIProvider`, because it reads the resolved configuration.

Where it sits in the tree does not change where a message appears: the queue is rendered
into a portal at the document body by default, which is how it escapes a scrolling panel's
overflow and a stacking context's z-index. What the position decides is *who can report*,
everything that calls `useToast()` has to be beneath it.

Two placements are mistakes:

- **Inside a route.** A provider that unmounts on navigation takes its queue with it, so a
  message fired just before the reader moved on disappears with the page that fired it.
- **A second, nested provider.** It starts a queue of its own, and every `useToast()`
  beneath it reports to the inner provider. Both queues draw into the same corner of the
  window, `maxToasts` applies twice, and the order of messages stops being one order.
  Nothing errors, which is exactly why it hides in review.

The hook degrades rather than throwing: outside a provider, `useToast()` returns no-op functions
and an empty `toasts` array. A missing provider is therefore a button that does nothing, not a
crash, so when a message does not appear, check the tree before the message. In development the
first such call also warns once, naming the likely mistakes (a missing provider, or a nested one),
because a button that silently does nothing is the hardest kind of bug to see and a warning on
every render would be the second.

## Message types

```tsx demo="feedback/toast-types"
```

The type decides the glyph and the colour role: `success` is success, `error` is danger,
`warning` is warning, `info` is primary, and the general `default` type is secondary for a
message that is neither praise nor blame. Every one of them is polite. A failure that has
to interrupt, or that describes the state of something on the page rather than the result of
a press, is an [Alert](/components/feedback/alert) at the `error` or `warning` intent.

## The queue and its timer

```tsx demo="feedback/toast-per-message"
```

A message waits 3500ms by default. `timeout` states its own wait; `0` keeps it until the
reader dismisses it. The timer starts when the message appears and **pauses while the
pointer is over it**, resuming with the time that was left rather than a fresh budget: a
message that vanished while it was being read, or while a control inside it was being
reached for, would punish the reader for paying attention.

`maxToasts` is 5. A new message arrives at the top of its stack and the oldest one beyond
the limit is dropped, because a queue deeper than a reader can read is a queue that hides
messages. Passing an `id` that is already in the queue **replaces** that message instead of
adding a second one, so a progress message can update in place.

`placement`, `size`, `variant`, `radius` and `animated` are stated on the provider and can
be overridden per message, a message that belongs to a panel at the bottom of the screen
does not have to arrive in the same corner as the rest. `dismissible={false}` removes the
close control; combined with `timeout: 0` it produces a message the reader cannot get rid
of, which is a decision to take deliberately. `action` is a node rendered under the message,
for the one thing the reader may want to do next.

The hook exposes the queue as well as filling it: `toasts` is the current array,
`removeToast(id)` drops one, and `clearToasts()` empties it.

## Props

```props ToastProvider
```

`size` (`md`), `placement` (`top-right`), `radius` (`md`), `animated` (`true`), `defaultTimeout`
(3500), `maxToasts` (5) and `portal` (`true`) are all registered under `components.toast`, so a
configuration file can state the queue's habits once and every provider inherits them; a prop on
the provider overrides the registered value, and an option on a single message overrides the
provider.

Two of the options behave differently from their siblings. `variant` is **not** registered, so a
toast follows the application's `defaultVariant` the way an alert does: the shipped configuration
makes that `faded`, and an application that sets `solid` gets solid toasts without saying so again,
state `components.toast.variant`, or the message's own `variant`, to pin one. `radius`, by contrast,
is registered, so the application's `defaultRadius` never reaches a toast; state
`components.toast.radius` to round the queue. `portal` is a web option: the platform has no document
to portal into.

## Accessibility

- Every message is `role="status"`, polite, so it is announced when the reader is idle
  rather than over the top of a sentence, and each message lives inside the stack's `<section>`,
  a named region a reader can also jump to. The name carries the placement, `Notifications (top
  right)`, `Notifications (bottom centre)`, because two stacks on one screen would otherwise
  offer the same name twice and say nothing about which corner each one is in.
- Nothing takes focus, and nothing should: a toast reports on an action without moving the
  reader away from where they acted. The dismiss control is a real button, named
  `Dismiss notification`, and sits in the tab order after the page's own content.
- The clock pauses for the pointer, not for focus. A keyboard reader tabbing towards a
  message's `action` can therefore lose it, so a message with an action that has to be
  reached should state `timeout: 0`.
- A toast says what the screen does not: the result of something the reader pressed. A
  message that repeats what is already visible is noise that interrupts the next thing.

Which surface announces which situation, and why some of them are deliberately silent, is
the subject of [Announcements](/concepts/announcements).

## Related

```related alert, spinner, button
```
