# Toasts
> Toast stack with pixel type icons and a draining timer bar that pauses on hover or focus; it can be pinned to a viewport corner.
- React: `import { PxToaster } from "@/components/lumesec/px-toaster"`
- Collection: Pixel UI (https://elements.lumesec.ai/components/pixel-ui)
- Registry item: https://elements.lumesec.ai/r/px-toaster.json
- Page: https://elements.lumesec.ai/components/pixel-ui/toaster



Live preview: https://elements.lumesec.ai/view/px-toaster

Demo source:

```tsx
"use client";

import * as React from "react";

import { PxToaster, type PxToasterHandle } from "@/components/lumesec/px-toaster";

const controlButton =
  "h-[30px] rounded-lg border border-border bg-card px-[11px] font-[inherit] text-[12.5px] font-medium text-foreground hover:border-[color-mix(in_srgb,var(--lumesec)_50%,var(--border))]";

export default function PxToasterDemo() {
  const toaster = React.useRef<PxToasterHandle>(null);

  React.useEffect(() => {
    const timer = window.setTimeout(
      () => toaster.current?.show({ title: "Changes saved", description: "Your settings are up to date.", type: "success", duration: 0 }),
      300,
    );
    return () => window.clearTimeout(timer);
  }, []);

  return (
    <div className="grid w-full max-w-[380px] gap-[14px]">
      <PxToaster ref={toaster} />
      <div className="flex flex-wrap justify-center gap-1.5">
        <button
          type="button"
          className={controlButton}
          onClick={() => toaster.current?.show({ title: "Changes saved", description: "Your settings are up to date.", type: "success" })}
        >
          Saved
        </button>
        <button
          type="button"
          className={controlButton}
          onClick={() => toaster.current?.show({ title: "Upload failed", description: "report.pdf is over the 30 MB limit.", type: "error" })}
        >
          Failed
        </button>
        <button
          type="button"
          className={controlButton}
          onClick={() =>
            toaster.current?.show({
              title: "3 files deleted",
              type: "info",
              duration: 6000,
              action: { label: "Undo", onClick: () => toaster.current?.show({ title: "Files restored", type: "success" }) },
            })
          }
        >
          With undo
        </button>
      </div>
    </div>
  );
}
```

## Playground

Change a prop and the component re-renders. Props marked remounts set an initial value, so the component starts over.

## Installation

```bash
npx shadcn@latest add @lumesec/px-toaster
```

First time with the @lumesec registry? Register it once, or install by URL:

```bash
npx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.json
npx shadcn@latest add https://elements.lumesec.ai/r/px-toaster.json
```

## Usage

React:

```tsx
import * as React from "react";

import { PxToaster, type PxToasterHandle } from "@/components/lumesec/px-toaster";

export function Example() {
  const toaster = React.useRef<PxToasterHandle>(null);
  return (
    <>
      <button type="button" onClick={() => toaster.current?.show({ title: "Changes saved", type: "success" })}>
        Save
      </button>
      <PxToaster ref={toaster} position="bottom-right" />
    </>
  );
}
```

## Behaviour

Stacked notifications with pixel icons and a draining timer that pauses while you hover. Add `position="bottom-right"` to pin it to the viewport.

## API reference

### Props

Also accepts every prop of `<div>` (`React.ComponentProps<"div">`), spread onto the root element.

| Prop        | Type                                             | Default | Description                                                                                                               |
| ----------- | ------------------------------------------------ | ------- | ------------------------------------------------------------------------------------------------------------------------- |
| `position`  | `"bottom-right" \| "bottom-left" \| "top-right"` | —       | Pins the stack to that viewport corner with `position: fixed`, up to 360 px wide. Without it the stack stays in the flow. |
| `max`       | `number`                                         | `4`     | Maximum toasts on screen; showing one more dismisses the oldest.                                                          |
| `onShow`    | `(id: number, type: PxToastType) => void`        | —       | Called when a toast is added.                                                                                             |
| `onDismiss` | `(id: number) => void`                           | —       | Called when a toast starts leaving: timer, dismiss button, action button, overflow or `dismiss()`.                        |

### Ref

`ref` receives a `PxToasterHandle` handle with these methods.

| Method                                 | Description                                                                                                                                                                                                                                                                                                                                                                                            |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `show(toast?: PxToastOptions): number` | Adds a toast and returns its id. `PxToastOptions` is `{ title?: React.ReactNode; description?: React.ReactNode; type?: "info" \| "success" \| "warning" \| "error"; duration?: number; action?: { label: string; onClick?: () => void } }`. `type` defaults to `info` and `duration` to 4500 ms; 0 or less keeps the toast until dismissed. The action button calls `onClick` and dismisses the toast. |
| `dismiss(id: number): void`            | Starts the exit of the toast with that id. Unknown or leaving ids are ignored.                                                                                                                                                                                                                                                                                                                         |

## Accessibility

* The stack is a `role="region"` with `aria-label="Notifications"` and `aria-live="polite"`.
* Each toast has `role="status"`; error toasts have `role="alert"`.
* Dismiss buttons are native buttons labelled "Dismiss"; action buttons use the action label.
* Hover or focus inside the stack pauses all timers.
* The type icons and timer bars are drawn on an `aria-hidden` canvas.
* Reduced motion: toasts appear and leave without the slide and collapse animations; the timer bars still drain.

## Theming

Styled with Tailwind classes on your shadcn theme tokens, so light and dark follow your theme. The accent comes from `--lumesec`. See [Theming](/docs/theming).

This component reads `--card`, `--border`, `--foreground`, `--muted-foreground`, `--muted`, `--lumesec`, `--lumesec-success`, `--lumesec-warning` and `--destructive`.

## Notes

* Toasts appear only through `show()` on the handle; `ref` is the handle, not the DOM element.
* Pinning uses `position: fixed` on the root, so an ancestor that creates a containing block for fixed-position descendants (for example through `filter` or `transform`) changes what it is fixed to.


