Toast Notifications
Relevant source files
The following files were used as context for generating this wiki page:The project includes two distinct systems for displaying toast notifications, which are small, non-intrusive messages that appear on the screen to provide feedback or information to the user. The first is a custom, state-managed system built using Radix UI Toast and inspired by react-hot-toast. The second is a wrapper around the popular sonner library, which is integrated with the application's theme.
The presence of both @radix-ui/react-toast and sonner as dependencies indicates that developers can choose the system that best fits their needs for a particular feature. The Radix-based system offers fine-grained control via a custom hook and reducer, while the Sonner-based system provides a simpler, theme-aware implementation out of the box.
Sources: frontend/package.json:30, frontend/package.json:50, frontend/src/hooks/use-toast.js:2
Architecture Overview
The application's architecture for toast notifications is split into two independent modules. A developer can use either the custom Radix-based system or the sonner library wrapper.
The following diagram illustrates the two separate notification systems available in the codebase.
System 1: Radix-based Toasts (use-toast)
This system provides a highly customizable toast implementation using a combination of a custom React hook, a state reducer, and UI components built on Radix UI.
Sources: frontend/src/hooks/use-toast.js, frontend/src/components/ui/toast.jsx, frontend/src/components/ui/toaster.jsx
Core Logic (use-toast.js)
The core logic resides in the use-toast.js hook. It manages a global state for toasts, allowing any component to create, update, or dismiss notifications.
State Management
A reducer function manages the toast state, which is an array of toast objects. It handles four action types.
| Action Type | Description |
|---|---|
ADD_TOAST | Adds a new toast to the state. The number of visible toasts is limited by TOAST_LIMIT (set to 1). |
UPDATE_TOAST | Updates an existing toast's properties by its ID. |
DISMISS_TOAST | Sets a toast's open property to false, triggering its exit animation. It then queues the toast for removal. |
REMOVE_TOAST | Removes a toast from the state array entirely after a delay (TOAST_REMOVE_DELAY). |
Sources: frontend/src/hooks/use-toast.js:5-12, frontend/src/hooks/use-toast.js:40-91
toast() Function
This is the primary function used to create a new notification. It returns an object with methods to control the created toast.
function toast({ ...props }) {
const id = genId()
const update = (props) =>
dispatch({
type: "UPDATE_TOAST",
toast: { ...props, id },
})
const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
dispatch({
type: "ADD_TOAST",
toast: {
...props,
id,
open: true,
onOpenChange: (open) => {
if (!open) dismiss()
},
},
})
return {
id: id,
dismiss,
update,
}
}
Sources: frontend/src/hooks/use-toast.js:107-133
useToast() Hook
Components use this hook to access the current list of toasts and the dismiss function.
function useToast() {
const [state, setState] = React.useState(memoryState)
React.useEffect(() => {
// ... listener logic ...
}, [state])
return {
...state,
toast,
dismiss: (toastId) => dispatch({ type: "DISMISS_TOAST", toastId }),
};
}
Sources: frontend/src/hooks/use-toast.js:135-151
Data Flow
The following sequence diagram shows how a component creates a toast and how it is rendered.
UI Components
The UI is composed of several React components that wrap the primitives from @radix-ui/react-toast.
toaster.jsx
The Toaster component is the main container that renders all active toasts. It uses the useToast hook to get the list of toasts and maps over them, rendering a <Toast> component for each one.
export function Toaster() {
const { toasts } = useToast()
return (
<ToastProvider>
{toasts.map(function ({ id, title, description, action, ...props }) {
return (
<Toast key={id} {...props}>
<div className="grid gap-1">
{title && <ToastTitle>{title}</ToastTitle>}
{description && (
<ToastDescription>{description}</ToastDescription>
)}
</div>
{action}
<ToastClose />
</Toast>
);
})}
<ToastViewport />
</ToastProvider>
);
}
Sources: frontend/src/components/ui/toaster.jsx:10-30
toast.jsx
This file exports all the building blocks for creating the visual representation of a toast.
| Component | Description |
|---|---|
ToastProvider | The provider component from Radix that scopes toast state. |
ToastViewport | A fixed-position container where toasts are rendered. |
Toast | The root component for an individual toast. It has default and destructive variants. |
ToastTitle | The title of the toast. |
ToastDescription | The body/description of the toast. |
ToastAction | An action button that can be included in a toast. |
ToastClose | A button to close the toast. |
Sources: frontend/src/components/ui/toast.jsx
The styling for these components is managed by Tailwind CSS and class-variance-authority (cva) for variants.
const toastVariants = cva(
// ... base classes ...
{
variants: {
variant: {
default: "border bg-background text-foreground",
destructive:
"destructive group border-destructive bg-destructive text-destructive-foreground",
},
},
defaultVariants: {
variant: "default",
},
}
)
Sources: frontend/src/components/ui/toast.jsx:21-36
System 2: Sonner-based Toasts
This system utilizes the sonner library, providing a simpler, alternative toast implementation. The file sonner.jsx acts as a configuration wrapper.
Implementation (sonner.jsx)
The Toaster component from sonner.jsx wraps the Sonner component from the sonner library. Its main purpose is to integrate with the application's theme (next-themes) and apply custom styling.
import { useTheme } from "next-themes"
import { Toaster as Sonner } from "sonner"
const Toaster = ({ ...props }) => {
const { theme = "system" } = useTheme()
return (
<Sonner
theme={theme}
className="toaster group"
toastOptions={{
classNames: {
// ... class names ...
},
}}
{...props} />
);
}
Sources: frontend/src/components/ui/sonner.jsx:1-22
Configuration
The toastOptions.classNames prop is used to override the default styles of sonner toasts with Tailwind CSS utility classes, ensuring a consistent look and feel with the rest of the application.
| Key | Description |
|---|---|
toast | Classes for the main toast container. |
description | Classes for the toast description text. |
actionButton | Classes for the primary action button. |
cancelButton | Classes for the cancel/secondary button. |