Skip to main content
React hook that provides access to the toast notification system. Built on top of Sonner for displaying temporary toast messages.

Signature

const useToast: () => typeof toast

Returns

Returns the toast function from Sonner with all its methods:
toast
function
Main toast function for displaying messages

Usage

Basic Toast

import { useToast } from "@tailor-platform/app-shell";

function MyComponent() {
  const toast = useToast();

  const handleClick = () => {
    toast("Hello, World!");
  };

  return <button onClick={handleClick}>Show Toast</button>;
}

Success Toast

import { useToast } from "@tailor-platform/app-shell";

function SaveButton() {
  const toast = useToast();

  const handleSave = async () => {
    try {
      await saveData();
      toast.success("Changes saved successfully!");
    } catch (error) {
      toast.error("Failed to save changes");
    }
  };

  return <button onClick={handleSave}>Save</button>;
}

Error Toast

import { useToast } from "@tailor-platform/app-shell";

function DeleteButton({ itemId }: { itemId: string }) {
  const toast = useToast();

  const handleDelete = async () => {
    try {
      await deleteItem(itemId);
      toast.success("Item deleted");
    } catch (error) {
      toast.error("Failed to delete item. Please try again.");
    }
  };

  return (
    <button onClick={handleDelete}>
      Delete
    </button>
  );
}

Loading Toast

import { useToast } from "@tailor-platform/app-shell";

function ExportButton() {
  const toast = useToast();

  const handleExport = async () => {
    const toastId = toast.loading("Exporting data...");
    
    try {
      await exportData();
      toast.success("Export complete!", { id: toastId });
    } catch (error) {
      toast.error("Export failed", { id: toastId });
    }
  };

  return <button onClick={handleExport}>Export</button>;
}

Promise Toast

import { useToast } from "@tailor-platform/app-shell";

function UploadButton() {
  const toast = useToast();

  const handleUpload = async () => {
    const uploadPromise = uploadFile();

    toast.promise(uploadPromise, {
      loading: "Uploading...",
      success: "File uploaded successfully!",
      error: "Upload failed",
    });
  };

  return <button onClick={handleUpload}>Upload</button>;
}

Toast with Description

import { useToast } from "@tailor-platform/app-shell";

function NotificationButton() {
  const toast = useToast();

  const showNotification = () => {
    toast.success("Order confirmed", {
      description: "Your order #12345 has been confirmed and will ship soon.",
    });
  };

  return <button onClick={showNotification}>Show Notification</button>;
}

Toast with Action

import { useToast } from "@tailor-platform/app-shell";

function UndoExample() {
  const toast = useToast();

  const handleDelete = (item: Item) => {
    // Delete the item
    deleteItem(item.id);

    toast.success("Item deleted", {
      action: {
        label: "Undo",
        onClick: () => restoreItem(item),
      },
    });
  };

  return <button onClick={() => handleDelete(item)}>Delete</button>;
}

Dismissing Toasts

import { useToast } from "@tailor-platform/app-shell";

function ToastControls() {
  const toast = useToast();

  const showToast = () => {
    const id = toast("This is a toast");
    
    // Dismiss this specific toast after 2 seconds
    setTimeout(() => {
      toast.dismiss(id);
    }, 2000);
  };

  const dismissAll = () => {
    // Dismiss all toasts
    toast.dismiss();
  };

  return (
    <div>
      <button onClick={showToast}>Show Toast</button>
      <button onClick={dismissAll}>Dismiss All</button>
    </div>
  );
}

Toast Options

All toast methods accept an optional options object:

Example: Form Submission

import { useToast } from "@tailor-platform/app-shell";
import { useState } from "react";

function UserForm() {
  const toast = useToast();
  const [formData, setFormData] = useState({ name: "", email: "" });

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();

    const submitPromise = fetch("/api/users", {
      method: "POST",
      body: JSON.stringify(formData),
    });

    toast.promise(submitPromise, {
      loading: "Creating user...",
      success: (response) => {
        setFormData({ name: "", email: "" });
        return "User created successfully!";
      },
      error: (error) => {
        console.error(error);
        return "Failed to create user. Please try again.";
      },
    });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={formData.name}
        onChange={(e) => setFormData({ ...formData, name: e.target.value })}
        placeholder="Name"
      />
      <input
        value={formData.email}
        onChange={(e) => setFormData({ ...formData, email: e.target.value })}
        placeholder="Email"
      />
      <button type="submit">Create User</button>
    </form>
  );
}

Best Practices

  1. Keep messages concise: Toast messages should be brief and scannable
  2. Use appropriate variants: Choose the right variant (success, error, warning) for the context
  3. Provide actionable feedback: Include action buttons when users can respond (e.g., “Undo”)
  4. Don’t overuse: Avoid showing multiple toasts simultaneously for unrelated actions
  5. Set appropriate duration: Longer messages may need longer display time
For more advanced usage and customization options, refer to the Sonner documentation.

Build docs developers (and LLMs) love