Skip to content
Highlight

V2 componentsUpdated Nov 3, 2026

Toast

A short confirmation that something just happened, pinned to the bottom centre and gone after five seconds. Use it for results the user caused ("Link copied", "Member removed" with Undo). Always dark in both themes: it is chrome over the page, so unlike Tooltip, which sits on the overlay surface, it does not follow the theme. One shows at a time: a new toast replaces the last in place, and the last waits underneath on its own timer, so dismissing the new one brings it back if it hasn’t expired. Up to three wait; hovering pauses every timer. Swipe one down or right to dismiss it. Never use it for anything the user must act on or can miss: errors that block work belong inline, and decisions belong in a Dialog. An action is at most one ghost button, in practice Undo.

Source: packages/ui/src/components/toast

tsx
import { Toast } from '@highlight/ui'

Change the props; the preview and the snippet update together.

Props
Tone
Undo action
tsx
const toast = Toast.useToast() <Button onClick={() => toast({ message: "Member removed", tone: 'success' })}>  Show toast</Button>

Wrap the app in Toast.Provider once, then call Toast.useToast() anywhere below it. A message, a message with one action, and either with a leading icon. All are 32px tall, so swapping one for another never moves the toast.

tsx
import { Button, Toast } from '@highlight/ui'import { Bookmark } from 'lucide-react' function Buttons() {  const toast = Toast.useToast()  return (    <div className="flex flex-wrap items-center justify-center gap-3">      <Button variant="secondary" onClick={() => toast({ message: 'Link copied' })}>        Message      </Button>      <Button        variant="secondary"        onClick={() => toast({ message: 'Member removed', action: { label: 'Undo', onClick: () => undefined } })}      >        Message and action      </Button>      <Button variant="secondary" onClick={() => toast({ message: 'Saved to bookmarks', icon: <Bookmark /> })}>        Icon      </Button>      <Button        variant="secondary"        onClick={() =>          toast({            message: 'Member removed',            tone: 'success',            action: { label: 'Undo', onClick: () => undefined },          })        }      >        Icon and action      </Button>    </div>  )} export default function ToastShapes() {  return (    <Toast.Provider>      <Buttons />    </Toast.Provider>  )}

success, info, warning and danger pick the default icon and colour only the icon. The surface never changes, so a danger toast is not a red slab arriving over the page.

tsx
import { Button, Toast, type ToastTone } from '@highlight/ui' const TONES: Array<{ tone: ToastTone; message: string }> = [  { tone: 'success', message: 'Changes saved' },  { tone: 'info', message: 'Sync paused while you are offline' },  { tone: 'warning', message: 'Storage is almost full' },  { tone: 'danger', message: 'Could not send the invite' },] function Buttons() {  const toast = Toast.useToast()  return (    <div className="flex flex-wrap items-center justify-center gap-3">      {TONES.map(({ tone, message }) => (        <Button key={tone} variant="secondary" onClick={() => toast({ message, tone })}>          {tone}        </Button>      ))}    </div>  )} export default function ToastTones() {  return (    <Toast.Provider>      <Buttons />    </Toast.Provider>  )}

An action gets its own toast. Undo returns the request; the button spins while it runs, then the toast becomes the result where it stands, with its timer restarted. If the request fails the same toast shows the error. One toast per thing that happened, never a second one stacked on the first.

tsx
import { Button, Toast } from '@highlight/ui' /** Stands in for the request an Undo makes. */function restoreMember(fail: boolean): Promise<void> {  return new Promise((resolve, reject) =>    setTimeout(() => (fail ? reject(new Error('Couldn’t restore Ada. Try again.')) : resolve()), 800),  )} function Buttons() {  const toast = Toast.useToast()  const remove = (fail: boolean) =>    toast({      message: 'Ada Lovelace removed',      action: {        label: 'Undo',        onClick: (removed) =>          restoreMember(fail).then(() =>            removed.update({ message: 'Ada Lovelace restored', tone: 'success', action: undefined }),          ),      },    })  return (    <div className="flex flex-wrap items-center justify-center gap-3">      <Button variant="secondary" onClick={() => remove(false)}>        Remove, then Undo      </Button>      <Button variant="secondary" onClick={() => remove(true)}>        Undo that fails      </Button>    </div>  )} export default function ToastUpdateInPlace() {  return (    <Toast.Provider>      <Buttons />    </Toast.Provider>  )}

The root, then any compound sub-components. Every part accepts className and forwards the rest of its props to the element or Base UI part beneath it.

Toast
A single toast surface: a 32px squircle rectangle (not a pill) that holds an icon, the message and an action. Toast.Provider renders these for you. Pass it a container and the toasts mount in that element’s flow instead of pinning to the window, for a surface that owns its toasts and places them itself.
Toast.Provider
Wrap the app. Renders the portal, the live-region viewport and the toasts. limit (how many wait underneath) defaults to 3, timeout to 5000; hovering pauses the timers.
Toast.useToast
Returns toast({ message, tone?, icon?, action?: { label, onClick }, timeout? }), which returns the id. toast.update(id, { ...fields }) rewrites that toast in place and restarts its timer; toast.close(id?) dismisses. An action’s onClick receives the toast: call toast.update to turn "Member removed" into "Member restored" where it stands instead of showing a second toast. Return a promise and the toast waits with the button spinning, then closes or shows the error.
Toast.createToastManager
For use outside React: pass it to Provider as toastManager, and wrap it with toasterFor(manager) to get the same toast(), toast.update() and toast.close() as useToast.
Toast.Viewport / Icon / Description / Action / Close
Low-level parts for custom composition inside Toast, which is the root.