Skip to Content
⭐️ Leave a star →
ComponentsToast

Toast

An imperative notification system. Wrap your app (or any subtree) in Toast.Provider, render a single Toast.Viewport somewhere, and call useToast().toast(...) from anywhere inside.

The Provider owns the queue; the Viewport renders each active toast through a render-prop, giving you total control over markup. Auto-dismiss timers are per-toast and pause on hover by default.

Features

Imperative useToast() API — fire toasts from any descendant.
Render-prop Viewport — bring your own markup per toast.
Per-toast duration; 0 keeps the toast persistent.
Auto-pause on pointer-enter / focus, resume on leave / blur.
Stable status values for success / warning / danger / info styling.
Re-firing a toast with the same id updates in place instead of stacking.

Example

import { Toast, useToast } from '@wire-ui/react' function App() { return ( <Toast.Provider> <Trigger /> <Toast.Viewport> {(t, dismiss) => ( <Toast.Root key={t.id}> <Toast.Title>{t.title}</Toast.Title> <Toast.Description>{t.description}</Toast.Description> <Toast.Close onClick={dismiss}>×</Toast.Close> </Toast.Root> )} </Toast.Viewport> </Toast.Provider> ) } function Trigger() { const { toast } = useToast() return <button onClick={() => toast({ title: 'Saved' })}>Save</button> }

useToast hook

useToast() returns { toast, dismiss, toasts }. Must be called from a descendant of Toast.Provider.

  • toast(input) — adds a toast, returns its id. If you pass an id and one already exists with that id, it’s replaced in place.
  • dismiss(id) — removes a toast.
  • toasts — the current queue (a reactive value: array in React, computed ref in Vue, signal getter in Solid).
import { useToast } from '@wire-ui/react' function SaveButton() { const { toast, dismiss } = useToast() return ( <button onClick={() => { const id = toast({ title: 'Uploading…', description: 'design-mock.png', duration: 0, // persistent until you dismiss }) setTimeout(() => { toast({ id, title: 'Uploaded', description: 'design-mock.png', status: 'success', duration: 3000 }) }, 2000) }}> Upload </button> ) }

Styling

The Viewport wraps each toast in a <div role="status" aria-live="polite" data-status="…">. Style based on data-status:

<Toast.Root className=" data-[status=success]:border-black data-[status=success]:bg-[#f5f5f5] data-[status=warning]:border-black data-[status=danger]:border-black data-[status=danger]:bg-black data-[status=danger]:text-white " />

Toast.Close is a Button primitive — use [data-hover], [data-focus-visible], [data-active] for interaction styling.

Using data attributes

[data-status="success"] { /* successful action */ } [data-status="warning"] { /* heads-up */ } [data-status="danger"] { /* error */ } [data-status="info"] { /* informational */ } button[data-hover] { /* close button hover */ } button[data-focus-visible] { /* close button keyboard focus */ }

Provider props

PropTypeDefaultDescription
defaultDurationnumber5000Auto-dismiss timeout (ms) applied to toasts that don’t specify one

Viewport props

Toast.Viewport takes a render-prop child: (toast: ToastData, dismiss: () => void) => ReactNode. It also accepts standard div props for styling (className, etc).

Toast input (toast(...) argument)

FieldTypeDefaultDescription
idstringauto-generatedStable id; re-firing with the same id replaces in place
titleReactNodeToast title
descriptionReactNodeToast description
status'default' | 'success' | 'warning' | 'danger' | 'info''default'Drives data-status for styling
durationnumberProvider’s defaultDurationAuto-dismiss after N ms. 0 or negative = persistent
pauseOnHoverbooleantruePause auto-dismiss while pointer or focus is inside
dataRecord<string, unknown>Arbitrary data passed through to the Viewport render-prop

Data attributes

AttributeElementValues
data-statusViewport shell wrapping each toast"default" / "success" / "warning" / "danger" / "info"

Accessibility

  • Each toast is wrapped in <div role="status" aria-live="polite"> so screen readers announce them as they appear.
  • The Viewport is <div role="region" aria-label="Notifications">.
  • Toast.Close is a real <button> with aria-label="Close notification".
  • Hovering or focusing a toast pauses its dismiss timer — users can read longer messages.

Keyboard Interactions

KeyDescription
TabMoves focus into the Viewport and through Close buttons; pauses the timer while focused.
Enter / SpaceActivates the focused Close button.

Internals

Since 0.3.0, each toast’s auto-dismiss timer is delegated to useTimeout — pause-on-hover and pause-on-focus reuse the same stop / reset controls. No public API change.

Last updated on

MIT License © 2026 wire-ui

Toast – Wire UI