Toast

Overlay & Feedback

Temporary notification message with auto-dismiss.

Preview

Usage

example.jsx
import { ToastProvider } from "@/components/ui/toast";

export default function Example() {
  return <ToastProvider />;
}

Source Code

Copy this file into components/ui/toast.jsx in your project.

toast.jsx
"use client";

import { createContext, useContext, useState, useCallback } from "react";
import { cn } from "@/lib/utils";

const ToastContext = createContext({ toasts: [], addToast: () => {}, removeToast: () => {} });

export function ToastProvider({ children }) {
  const [toasts, setToasts] = useState([]);
  const addToast = useCallback((toast) => {
    const id = Date.now();
    setToasts((prev) => [...prev, { ...toast, id }]);
    setTimeout(() => setToasts((prev) => prev.filter((t) => t.id !== id)), toast.duration || 5000);
    return id;
  }, []);
  const removeToast = useCallback((id) => setToasts((prev) => prev.filter((t) => t.id !== id)), []);

  return (
    <ToastContext.Provider value={{ toasts, addToast, removeToast }}>
      {children}
      <div className="fixed bottom-4 right-4 z-[100] flex flex-col gap-2">
        {toasts.map((toast) => (
          <div key={toast.id} className={cn("flex items-center justify-between gap-4 rounded-lg border bg-background px-4 py-3 shadow-lg animate-in slide-in-from-bottom-5",
            toast.variant === "destructive" && "border-destructive bg-destructive text-destructive-foreground"
          )}>
            <div>
              {toast.title && <div className="text-sm font-semibold">{toast.title}</div>}
              {toast.description && <div className="text-sm text-muted-foreground">{toast.description}</div>}
            </div>
            <button onClick={() => removeToast(toast.id)} className="shrink-0 rounded-sm opacity-70 hover:opacity-100">
              <svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" /></svg>
            </button>
          </div>
        ))}
      </div>
    </ToastContext.Provider>
  );
}

export function useToast() {
  const ctx = useContext(ToastContext);
  return { toast: ctx.addToast, dismiss: ctx.removeToast, toasts: ctx.toasts };
}

Quick Install

Make sure you have the cn() utility set up. It requires clsx and tailwind-merge.

npm install clsx tailwind-merge