Toast

A short message that appears over the page for a moment, to confirm something that just happened.

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

OptionTypeDefault
title / descriptionReactNodenone
type"success" | "error" | "warning" | "info" | "loading"none
timeoutnumber (ms)5000
priority"low" | "high""low"
actionPropsprops of a buttonnone
idstringA new id

Toaster

PropTypeDefault
position"top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right""bottom-right"
padding"sm" | "md" | "lg""md"

AnchoredToaster

PropTypeDefault
side"top" | "bottom" | "left" | "right""top"
sideOffsetnumber8
padding"sm" | "md" | "lg""md"