Toast
A temporary notification that stacks in a corner of the screen, or anchors to a specific element on the page. Built on Base UI's toast primitive, with swipe-to-dismiss and success/error/warning/ info/loading statuses.
Last updated January 1, 1980
Copied from shadcn/ui and coss ui.
- Adds a logical position="start"/"end" (on both ToastProvider's corner and the physical left/right CSS it drives) on top of coss ui's literal left/right/center, resolved from the ambient direction measured where the provider's children actually render — matching the pattern already used by Dialog/Drawer/Tooltip for portaled content
- ToastProvider and AnchoredToastProvider explicitly set dir on the portaled Viewport/Positioner from that same measurement, so swipe-to-dismiss direction and logical spacing resolve correctly even when the provider sits in an otherwise-LTR page
- Merges shadcn's per-slot exported pieces (ToastTitle/ToastDescription/ToastAction/ToastClose, and an explicit close button) with coss ui's position-aware viewport, stacking math, and AnchoredToastProvider
- Adds an "x" variant (compact rounded-full pill with an avatar/icon slot, in the style of X's native in-app notifications) on top of both sources' plain card style, selected per-toast via `data: { variant: "x" }`
- Aligns the leading icon/avatar to the title line (items-start) instead of centering it against the combined title+description block
- Adds a per-toast `data: { dir }` override so a toast's content direction can be forced regardless of the provider's ambient/measured direction — the provider's corner position still follows the ambient direction, only the toast's own text/logical spacing is overridden
- Dropped coss ui's custom swipe-replay keyframes (bounce-on-update, shake-on-error) — this repo's registry has no mechanism yet for shipping component-scoped @keyframes, unlike coss ui's registry-item cssVars/css fields
Overview
Installation
Usage
Call toastManager.add() from anywhere in your app after adding the provider to your root layout — no hook needed, since the manager is a plain module-level instance.
import { Button } from "@/components/ui/button"
import { toastManager } from "@/components/ui/toast"
export function Example() {
return (
<Button
variant="outline"
onClick={() =>
toastManager.add({
title: "Event created",
description: "Sunday, December 3 at 9:00 AM",
})
}
>
Show toast
</Button>
)
}Examples
Statuses
Pass type to pick the leading icon and its color: success, error, warning, info, or loading. Update a loading toast in place with toastManager.update(id, options).
X style
Set data: { variant: "x" } for a compact, rounded-full pill in the style of X's native in-app notifications, with an avatar or icon slot.
Anchored toast
Wrap in AnchoredToastProvider and call anchoredToastManager.add({ positionerProps: { anchor } }) to position a toast against a specific element — a tooltip-like confirmation next to the button that triggered it — instead of stacking it in a screen corner. The smallest way to see it in action is Copy Button, a small building block that anchors its own copy confirmation this way — the Dialog and Drawer examples below use it too.
import { CopyButton } from "@/components/ui/copy-button"
export function Example() {
return <CopyButton text="https://persian-labs.ir" />
}Standalone
From a Dialog
From a Drawer
RTL
By default every position — including the centered ones — mirrors automatically: start lands on the right in RTL and the left in LTR (and vice versa for end), matching the ambient dir the provider measures from its parent. To force a toast's content direction regardless of the ambient page direction — e.g. Persian content on an otherwise-LTR page — pass data: { dir: "rtl" } per call, as this example does rather than relying on the page direction toggle.