Toast
Lightweight context-based toast system. No external library. 4 types, auto-dismiss, slide-up animation, accessible.
Setup
ToastProvider wraps the app in app/layout.tsx. ToastContainer renders the toasts. Both are already set up in the scaffold:
app/layout.tsx
import { ToastProvider } from '@/hooks/useToast'
import { ToastContainer } from '@/components/ui/Toast'
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<ToastProvider>
{children}
<ToastContainer />
</ToastProvider>
</body>
</html>
)
}Using useToast
'use client'
import { useToast } from '@/hooks/useToast'
export function SomeComponent() {
const { toast, dismiss } = useToast()
function handleAction() {
toast('success', 'Changes saved successfully.')
toast('error', 'Something went wrong.')
toast('info', 'Your session expires in 5 minutes.')
toast('warning', 'This action cannot be undone.', 6000)
// ^^^^ custom duration ms
}
}Toast types
| Type | Icon | Use case |
|---|---|---|
| success | CheckCircle | Successful operations - saved, verified, updated |
| error | XCircle | Failures - server errors, validation failures |
| info | Info | Neutral information - session warnings, tips |
| warning | AlertTriangle | Caution - irreversible actions, expiry notices |
ToastContainer
ToastContainer renders a fixed stack of toasts:
- Position: bottom-right on desktop, bottom-center on mobile
- Max 5 toasts visible - oldest removed when limit exceeded
- Each toast: slide-up + fade-in on appear, reverse on remove
- Close button on each toast
- role=alert aria-live=polite for screen readers
- Default duration: 4000ms. Pass a 4th arg to toast() to override.
Customising
To change default duration, update the DEFAULT_DURATION constant in hooks/useToast.tsx. To change position, update ToastContainer's positioning classes in components/ui/Toast.tsx.