An opinionated toast component for React providing comprehensive toast notifications with customization options
npx @tessl/cli install tessl/npm-sonner@1.7.0Sonner is an opinionated toast component for React that provides a comprehensive solution for displaying toast notifications. It offers a simple and intuitive API through a Toaster component and toast function, supporting various toast types including success, error, info, warning, loading, and custom toasts with actions.
npm install sonnerimport { Toaster, toast } from "sonner";For CommonJS:
const { Toaster, toast } = require("sonner");Additional imports for advanced usage:
import {
Toaster,
toast,
useSonner,
type ExternalToast,
type ToasterProps,
type ToastT
} from "sonner";import React from "react";
import { Toaster, toast } from "sonner";
function App() {
return (
<div>
{/* Add Toaster component once in your app */}
<Toaster />
{/* Create toasts from anywhere */}
<button onClick={() => toast("Hello World!")}>
Show Toast
</button>
<button onClick={() => toast.success("Success!")}>
Success Toast
</button>
<button onClick={() => toast.error("Something went wrong!")}>
Error Toast
</button>
</div>
);
}Sonner is built around several key components:
Primary toast creation functions for displaying notifications with different visual styles and behaviors.
function toast(message: string | React.ReactNode, options?: ExternalToast): string | number;
// Type-specific toast functions
namespace toast {
function success(message: string | React.ReactNode, options?: ExternalToast): string | number;
function error(message: string | React.ReactNode, options?: ExternalToast): string | number;
function info(message: string | React.ReactNode, options?: ExternalToast): string | number;
function warning(message: string | React.ReactNode, options?: ExternalToast): string | number;
function loading(message: string | React.ReactNode, options?: ExternalToast): string | number;
function message(message: string | React.ReactNode, options?: ExternalToast): string | number;
function dismiss(id?: string | number): string | number | undefined;
function promise<T>(promise: PromiseT<T>, options: PromiseData<T>): { unwrap(): Promise<T> } & (string | number);
function custom(jsx: (id: string | number) => React.ReactElement, options?: ExternalToast): string | number;
function getHistory(): ToastT[];
function getToasts(): ToastT[];
}The main React component that renders and manages all toast notifications with comprehensive configuration options.
const Toaster: React.ForwardRefExoticComponent<ToasterProps & React.RefAttributes<HTMLElement>>;
interface ToasterProps {
invert?: boolean;
theme?: "light" | "dark" | "system";
position?: "top-left" | "top-right" | "bottom-left" | "bottom-right" | "top-center" | "bottom-center";
hotkey?: string[];
richColors?: boolean;
expand?: boolean;
duration?: number;
gap?: number;
visibleToasts?: number;
closeButton?: boolean;
toastOptions?: ToastOptions;
className?: string;
style?: React.CSSProperties;
offset?: Offset;
mobileOffset?: Offset;
dir?: "rtl" | "ltr" | "auto";
swipeDirections?: SwipeDirection[];
/** @deprecated Use icons prop instead */
loadingIcon?: React.ReactNode;
icons?: ToastIcons;
containerAriaLabel?: string;
pauseWhenPageIsHidden?: boolean;
}Advanced toast functionality including promise integration, custom JSX content, and action buttons.
// Promise-based toasts
function toast.promise<T>(
promise: Promise<T> | (() => Promise<T>),
options: PromiseData<T>
): { unwrap(): Promise<T> } & (string | number);
// Custom JSX toasts
function toast.custom(
jsx: (id: string | number) => React.ReactElement,
options?: ExternalToast
): string | number;
// Toast state management
function toast.getHistory(): ToastT[];
function toast.getToasts(): ToastT[];React hooks for integrating with toast state and managing toast notifications programmatically.
function useSonner(): {
toasts: ToastT[];
};interface ExternalToast {
id?: string | number;
type?: "normal" | "action" | "success" | "info" | "warning" | "error" | "loading" | "default";
icon?: React.ReactNode;
jsx?: React.ReactNode;
richColors?: boolean;
invert?: boolean;
closeButton?: boolean;
dismissible?: boolean;
description?: (() => React.ReactNode) | React.ReactNode;
duration?: number;
action?: Action | React.ReactNode;
cancel?: Action | React.ReactNode;
onDismiss?: (toast: ToastT) => void;
onAutoClose?: (toast: ToastT) => void;
cancelButtonStyle?: React.CSSProperties;
actionButtonStyle?: React.CSSProperties;
style?: React.CSSProperties;
unstyled?: boolean;
className?: string;
classNames?: ToastClassnames;
descriptionClassName?: string;
position?: Position;
}
interface Action {
label: React.ReactNode;
onClick: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
actionButtonStyle?: React.CSSProperties;
}
interface ToastT {
id: number | string;
title?: (() => React.ReactNode) | React.ReactNode;
type?: "normal" | "action" | "success" | "info" | "warning" | "error" | "loading" | "default";
icon?: React.ReactNode;
jsx?: React.ReactNode;
richColors?: boolean;
invert?: boolean;
closeButton?: boolean;
dismissible?: boolean;
description?: (() => React.ReactNode) | React.ReactNode;
duration?: number;
delete?: boolean;
action?: Action | React.ReactNode;
cancel?: Action | React.ReactNode;
onDismiss?: (toast: ToastT) => void;
onAutoClose?: (toast: ToastT) => void;
promise?: Promise<any> | (() => Promise<any>);
cancelButtonStyle?: React.CSSProperties;
actionButtonStyle?: React.CSSProperties;
style?: React.CSSProperties;
unstyled?: boolean;
className?: string;
classNames?: ToastClassnames;
descriptionClassName?: string;
position?: Position;
}
type Position = "top-left" | "top-right" | "bottom-left" | "bottom-right" | "top-center" | "bottom-center";
type SwipeDirection = "top" | "right" | "bottom" | "left";
interface ToastClassnames {
toast?: string;
title?: string;
description?: string;
loader?: string;
closeButton?: string;
cancelButton?: string;
actionButton?: string;
success?: string;
error?: string;
info?: string;
warning?: string;
loading?: string;
default?: string;
content?: string;
icon?: string;
}
interface ToastIcons {
success?: React.ReactNode;
info?: React.ReactNode;
warning?: React.ReactNode;
error?: React.ReactNode;
loading?: React.ReactNode;
close?: React.ReactNode;
}
type Offset = {
top?: string | number;
right?: string | number;
bottom?: string | number;
left?: string | number;
} | string | number;
interface PromiseData<ToastData = any> {
loading?: string | React.ReactNode;
success?: string | React.ReactNode | ((data: ToastData) => React.ReactNode | string | Promise<React.ReactNode | string>);
error?: string | React.ReactNode | ((error: any) => React.ReactNode | string | Promise<React.ReactNode | string>);
description?: string | React.ReactNode | ((data: any) => React.ReactNode | string | Promise<React.ReactNode | string>);
finally?: () => void | Promise<void>;
}
type PromiseT<Data = any> = Promise<Data> | (() => Promise<Data>);
type PromiseExternalToast = Omit<ExternalToast, 'description'>;