# Toast

Shows a short message that appears after an action and goes away by itself, such as "Settings saved".

- **Import:** `import { Toaster } from "@booleanpress/ui/sonner"`
- **Also install:** `sonner`
- **APG Alert:** <https://www.w3.org/WAI/ARIA/apg/patterns/alert/>
- **Page:** <https://ui.booleanpress.com/components/sonner> · @booleanpress/ui 0.1.0

## Usage

Render `Toaster` once, near the root of the app, inside `BooleanUIProvider`. Anywhere else, call `toast` from the `sonner` package. The package does not wrap `toast`, so Sonner's own documentation applies to it.

```tsx
import { toast } from "sonner"
import { Button } from "@booleanpress/ui/button"
import { Toaster } from "@booleanpress/ui/sonner"

export function App() {
  return (
    <>
      <Button onClick={() => toast.success("Settings saved")}>Save</Button>
      <Toaster />
    </>
  )
}
```

`Toaster` sets, for every product: coloured status toasts, a close button, 4 seconds on screen, at most 3 visible at once, a 12 px radius and a width of `min(24rem, 100vw − 2rem)`. It also takes the direction, the region's name and the close button's name from the provider (`notifications` and `closeNotification`).

The app passes its theme: `theme` is `"light"`, `"dark"` or `"system"` (the default). It does not read a theme provider of its own. `position`, `offset` and `mobileOffset` are Sonner's: BooleanSMTP sets them to clear the WordPress admin bar.

`toast(message, options)` returns an id. The options used most are `description`, `action` (`{ label, onClick }`), `duration` and `id`; `toast.success`, `toast.error`, `toast.warning`, `toast.info` set the type, `toast.promise` follows a promise, and `toast.dismiss(id)` closes one. Pass `toasterId` and give `Toaster` the same `id` only when a page has more than one `Toaster`, as the examples on this site do.

## Examples

### Default

A plain message, with the close button and the 4-second timeout.

```tsx
import { toast } from "sonner"
import { Button } from "@booleanpress/ui/button"
import { Toaster } from "@booleanpress/ui/sonner"

export default function SonnerDefault() {
  return (
    <>
      <Button variant="outline" onClick={() => toast("Settings saved", { toasterId: "sonner-default" })}>
        Save settings
      </Button>
      <Toaster id="sonner-default" />
    </>
  )
}
```

### Status

`toast.success`, `error`, `warning` and `info`, each with its icon and its status colours.

```tsx
import { toast } from "sonner"
import { Button } from "@booleanpress/ui/button"
import { Toaster } from "@booleanpress/ui/sonner"

const toasterId = "sonner-status"

export default function SonnerStatus() {
  return (
    <>
      <div className="flex flex-wrap justify-center gap-2">
        <Button variant="outline" onClick={() => toast.success("Test email delivered", { toasterId })}>
          Success
        </Button>
        <Button variant="outline" onClick={() => toast.error("The mailer rejected the email", { toasterId })}>
          Error
        </Button>
        <Button variant="outline" onClick={() => toast.warning("Your API key expires soon", { toasterId })}>
          Warning
        </Button>
        <Button variant="outline" onClick={() => toast.info("The backup mailer is in use", { toasterId })}>
          Info
        </Button>
      </div>
      <Toaster id={toasterId} />
    </>
  )
}
```

### Description and action

A second line of text and an action button, such as Undo.

```tsx
import { toast } from "sonner"
import { Button } from "@booleanpress/ui/button"
import { Toaster } from "@booleanpress/ui/sonner"

const toasterId = "sonner-description-action"

export default function SonnerDescriptionAction() {
  function remove() {
    toast("Routing rule deleted", {
      toasterId,
      description: "Emails to example.com use the default mailer again.",
      action: { label: "Undo", onClick: () => toast.success("Routing rule restored", { toasterId }) },
    })
  }

  return (
    <>
      <Button variant="outline" onClick={remove}>
        Delete the rule
      </Button>
      <Toaster id={toasterId} />
    </>
  )
}
```

### Promise

`toast.promise` shows a spinner while the request runs, then the success or error message.

```tsx
import { toast } from "sonner"
import { Button } from "@booleanpress/ui/button"
import { Toaster } from "@booleanpress/ui/sonner"

const toasterId = "sonner-promise"

export default function SonnerPromise() {
  function sendTest() {
    const request = new Promise<string>((resolve) => window.setTimeout(() => resolve("hello@example.com"), 2000))
    toast.promise(request, {
      toasterId,
      loading: "Sending the test email…",
      success: (to) => `Test email sent to ${to}`,
      error: "The test email failed",
    })
  }

  return (
    <>
      <Button variant="outline" onClick={sendTest}>
        Send a test email
      </Button>
      <Toaster id={toasterId} />
    </>
  )
}
```

## Accessibility

**Semantics.** Sonner renders a `section` named "Notifications Alt+T" (the name comes from the provider, then the hotkey). Each toast is a list item with its own live-region text; the close button is a `button` named from the provider.

**Labels.** Pass translated `notifications` and `closeNotification` strings to `BooleanUIProvider`. Write the message so it makes sense without the colour or the icon, and give an action a button label that names what it does ("Undo", not "OK").

**Focus.** Toasts do not take focus when they appear. Alt+T moves focus into the notification list; Tab then reaches each toast, its action and its close button. Hovering or focusing a toast pauses its timer.

**Known limits.**

- A toast leaves after 4 seconds, which is too short to read for some people, and a screen reader may be reading something else. Never put the only copy of an error, or anything that needs a decision, in a toast: show it in the page too (an `Alert` or a field error).
- An action in a toast can disappear before it is reached by keyboard. Offer the same action somewhere permanent.
- At most 3 toasts are visible; the rest queue behind them and are not announced until they show.

### Keyboard

| Key | Behaviour |
| --- | --- |
| Alt + T | Moves focus to the list of notifications. |
| Tab | Moves between the toasts, their action buttons and their close buttons. |
| Enter | On the close button, closes the toast. On an action button it activates it, as for any button. |
| Space | On the close button, closes the toast. On an action button it activates it, as for any button. |

## API

### Toaster

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `className` | `string` |  |  |
| `closeButton` | `boolean` |  |  |
| `containerAriaLabel` | `string` |  |  |
| `customAriaLabel` | `string` |  |  |
| `dir` | `"auto" \| "ltr" \| "rtl"` |  |  |
| `duration` | `number` |  |  |
| `expand` | `boolean` |  | Shows every toast open instead of stacked. |
| `gap` | `number` |  | The space between open toasts, in pixels. |
| `hotkey` | `string[]` |  | The keys that focus the list. The default is Alt+T. |
| `icons` | `ToastIcons` |  |  |
| `id` | `string` |  | Names this toaster. Only toasts sent with the same `toasterId` appear in it; needed only when a page has more than one. |
| `invert` | `boolean` |  |  |
| `mobileOffset` | `Offset` |  | The same, below 600 px. |
| `offset` | `Offset` |  | The distance from the edge of the window, as a number, a CSS length, or an object with `top`, `right`, `bottom`, `left`. |
| `position` | `"top-left" \| "top-right" \| "bottom-left" \| "bottom-right" \| "top-center" \| "bottom-center"` |  | Where the stack sits: `top-right`, `bottom-right` (the default) and the other four corners and centres. |
| `richColors` | `boolean` |  |  |
| `style` | `CSSProperties` |  |  |
| `swipeDirections` | `SwipeDirection[]` |  |  |
| `theme` | `"light" \| "dark" \| "system"` | `system` | `light`, `dark` or `system` (the default). Pass the app's own theme. |
| `toastOptions` | `ToastOptions` |  | Defaults for every toast, such as `duration` or `classNames`. The package's class names are kept unless you set the same part. |
| `visibleToasts` | `number` |  |  |

Every part takes `className`, merged with its defaults by `cn()`, and `ref`, which reaches the element it renders.

**Provider strings:** `notifications`, `closeNotification` (`BooleanUIProvider`'s `strings`).

## Theming

Each status type draws its fill and border from the status token (`--success`, `--info`, `--warning`, `--destructive`) mixed into `--popover`, and keeps the text in `--popover-foreground`. The plain toast uses `--popover`, `--popover-foreground` and `--border`; the action button uses `--primary`. Override any of Sonner's CSS variables with `style`, and the part classes with `toastOptions.classNames`: yours are merged over the package's.

| Token | Used for |
| --- | --- |
| `--destructive` | text |
| `--info` | text |
| `--muted-foreground` | text |
| `--success` | text |
| `--warning` | text |
