Desktop Notifications

Toast notifications for desktop and web — brief, non-blocking messages that appear in a screen corner to confirm actions, surface warnings, or report errors. Portaled to document.body; never interrupt flow.

Preview

Toast appears bottom-right and auto-dismisses after 4 s

Variants

VariantIcon colorUse when
infoBlueNeutral updates, tips, new features.
successGreenConfirmed saves, completed tasks, successful sends.
warningAmberNon-blocking issues the user should know about but can continue.
errorRedFailed operations. Set duration=0 so it persists until the user dismisses.

Position

ValueBest for
bottom-rightDefault. Non-intrusive; far from primary content focus.
top-rightApps with bottom-anchored toolbars or navigation.
bottom-centerMobile web or narrow viewports.
top-centerCritical alerts that need to be seen immediately.

Implementation

The Toast renders via createPortal to document.body — it is never clipped by overflow: hidden ancestors. Auto-dismiss runs a setTimeout that is cleared if the user dismisses early or the component unmounts.

Toast.tsx
tsx
import { useState } from "react";
import { Toast } from "@/components/ui/Toast";
import { Button } from "@/components/ui/Button";

export function Example() {
  const [open, setOpen] = useState(false);

  return (
    <>
      <Button onClick={() => setOpen(true)}>Save changes</Button>

      <Toast
        open={open}
        onClose={() => setOpen(false)}
        variant="success"
        title="Changes saved"
        description="Your profile has been updated."
        position="bottom-right"
        action={{ label: "Undo", onClick: () => console.log("undo") }}
      />
    </>
  );
}

Props

PropTypeDefaultDescription
open*booleanControls visibility. Toast unmounts when false.
onClose*() => voidCalled when the timer expires or the user dismisses.
title*stringPrimary message. Keep under 60 chars.
descriptionstringSupporting detail. Optional; 1–2 lines.
variant"info" | "success" | "warning" | "error""info"Controls icon and icon color.
durationnumber4000Auto-dismiss delay in ms. Pass 0 to disable auto-dismiss.
position"top-right" | "bottom-right" | "bottom-center" | "top-center""bottom-right"Screen corner where the toast appears.
action{ label: string; onClick: () => void }Optional inline action button.

Accessibility

  • Use role="status" and aria-live="polite" for informational toasts. Screen readers announce the content at the next natural pause.
  • For urgent error toasts, switch to role="alert" and aria-live="assertive" — the announcement interrupts the current reading flow.
  • aria-atomic="true" ensures the full toast content is read at once rather than character by character as text updates.
  • Never auto-dismiss error toasts (duration=0). Users may need to read error messages carefully or copy details. Auto-dismiss only low-urgency variants.
  • The close button must be reachable by keyboard. Focus should not automatically move to the toast — it is supplementary information, not a blocking dialog.
  • Respect prefers-reduced-motion: remove slide-in animation while keeping the visual appearance. The toast should still appear; just without motion.