import { Button } from "@hel/ui/button"
import { ToastProvider, Toaster, useToast } from "@hel/ui/toast"
When to use it#
Use a toast to confirm something that just happened and does not need an answer: "Invoice saved", "Link copied", "Message archived". It slides in, waits a few seconds, and goes away on its own.
A toast should never be the only place a message is shown. People may be looking elsewhere and miss it, so do not use it for errors that people must act on, such as a form that failed to save. Show those on the page, with an Alert or a Field error. For a message that stays until it stops being true, use an Alert. For a question that must be answered, use an Alert Dialog.
Import#
import {
ToastProvider,
Toaster,
AnchoredToaster,
useToast,
createToastManager,
} from "@hel/ui/toast"Setup#
Mount one ToastProvider and one Toaster near the root of your app, and every component below them can show a toast.
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ToastProvider>
{children}
<Toaster />
</ToastProvider>
)
}Then call useToast in any component, and add a toast. The examples on this page each have a provider of their own, so they work on their own, and the toasts appear in the corner of the screen.
const toast = useToast()
toast.add({ title: "Invoice saved", description: "INV-2041 was saved as a draft." })A toast goes away after 5 seconds. Hover or focus the stack to pause the timers and to spread out the toasts. Each toast can be swiped toward the nearest edge to dismiss it, and the whole stack is a region that screen reader users can jump to with F6.
Examples#
Types#
type picks the icon and the look: success, error, warning, info, or loading. Give an error priority: "high" so screen readers announce it right away.
import { Button } from "@hel/ui/button"
import { Flex } from "@hel/ui/flex"
import { ToastProvider, Toaster, useToast } from "@hel/ui/toast"Undo and promises#
actionProps adds a button to the toast. It takes the props of a button, so children is its label and onClick is what it does. Closing the first toast and adding a second is the classic undo pattern, and add returns the id you close it with.
toast.promise follows a promise. It shows a loading toast that turns into a success or an error toast when the promise settles, so you do not write the three states yourself.
import { Button } from "@hel/ui/button"
import { Flex } from "@hel/ui/flex"
import { ToastProvider, Toaster, useToast } from "@hel/ui/toast"Position#
position on the Toaster is one of six places, and the stack grows away from the edge it is anchored to. padding is sm, md or lg, and sets the space inside each toast. Toasts hold up to 3 at once, and older ones fade as new ones arrive.
import * as React from "react"
import { Button } from "@hel/ui/button"Anchored to an element#
For feedback about one thing, such as "Link copied" on the button that was pressed, pin the toast to that element. Anchored toasts have their own manager and AnchoredToaster. Pass the element as positionerProps.anchor when you add the toast. They show an arrow toward the anchor.
import * as React from "react"
import { Link2 } from "lucide-react"
Outside of React#
createToastManager() makes a manager you can call from anywhere, such as an API client or a utility, without a hook. Give it to the provider with toastManager.
export const toasts = createToastManager()
<ToastProvider toastManager={toasts}>...</ToastProvider>
// anywhere
toasts.add({ type: "error", title: "Could not reach the server" })Staying and updating#
timeout: 0 keeps a toast until it is dismissed, which suits something that needs a decision. Adding a toast with an id that exists updates that toast in place and restarts its timer, instead of adding another one, so saving a draft many times shows one toast.
Props#
toast.add#
| Option | Type | Default |
|---|---|---|
title / description | ReactNode | none |
type | "success" | "error" | "warning" | "info" | "loading" | none |
timeout | number (ms) | 5000 |
priority | "low" | "high" | "low" |
actionProps | props of a button | none |
id | string | A new id |
Toaster#
| Prop | Type | Default |
|---|---|---|
position | "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right" | "bottom-right" |
padding | "sm" | "md" | "lg" | "md" |
AnchoredToaster#
| Prop | Type | Default |
|---|---|---|
side | "top" | "bottom" | "left" | "right" | "top" |
sideOffset | number | 8 |
padding | "sm" | "md" | "lg" | "md" |