Next.js Integration
React Toast Kit works with both the Next.js App Router and Pages Router. Below are setup guides, patterns, and things to avoid.
Live Demo
This page runs inside a Next.js App Router app — try it:
App Router Setup
The simplest approach: add 'use client' to your root layout and wrap the body with ToastProvider.
1// app/layout.tsx
2'use client'; // Required when using hooks inside the layout
3
4import { ToastProvider } from 'react-toast-kit';
5import './globals.css';
6
7export default function RootLayout({ children }: { children: React.ReactNode }) {
8 return (
9 <html lang="en">
10 <body>
11 <ToastProvider theme="system" position="top-right">
12 {children}
13 </ToastProvider>
14 </body>
15 </html>
16 );
17}Recommended: To preserve Server Component benefits on the root layout, extract ToastProvider into a separate client wrapper component.
1// app/layout.tsx (Server Component — recommended pattern)
2import type { Metadata } from 'next';
3import './globals.css';
4import ToastWrapper from './ToastWrapper'; // client component
5
6export const metadata: Metadata = { title: 'My App' };
7
8export default function RootLayout({ children }: { children: React.ReactNode }) {
9 return (
10 <html lang="en">
11 <body>
12 <ToastWrapper>{children}</ToastWrapper>
13 </body>
14 </html>
15 );
16}
17
18// app/ToastWrapper.tsx
19'use client';
20import { ToastProvider } from 'react-toast-kit';
21
22export default function ToastWrapper({ children }: { children: React.ReactNode }) {
23 return <ToastProvider theme="system">{children}</ToastProvider>;
24}Pages Router Setup
Add ToastProvider to your _app.tsx file:
1// pages/_app.tsx (Pages Router)
2import type { AppProps } from 'next/app';
3import { ToastProvider } from 'react-toast-kit';
4import '../styles/globals.css';
5
6export default function MyApp({ Component, pageProps }: AppProps) {
7 return (
8 <ToastProvider theme="system" position="top-right">
9 <Component {...pageProps} />
10 </ToastProvider>
11 );
12}Using in Client Components
toast() calls the Zustand store — it only runs in the browser. Always import and call it inside 'use client' components.
1'use client'; // Required — toast() cannot be called in Server Components
2
3import { toast } from 'react-toast-kit';
4
5export default function LoginButton() {
6 const handleLogin = async () => {
7 try {
8 await signIn(credentials);
9 toast.success({ title: 'Welcome back!', description: 'You are now signed in.' });
10 } catch (err) {
11 toast.error({ title: 'Login failed', description: err.message });
12 }
13 };
14
15 return <button onClick={handleLogin}>Sign in</button>;
16}Server Actions Pattern
Server Actions run on the server — you cannot call toast() inside them. Instead, return the result to the client and toast from there.
1// app/actions.ts (Server Action)
2'use server';
3
4export async function saveData(formData: FormData) {
5 await db.save(formData);
6 // ✗ Cannot call toast() here — Server Action runs on the server
7 return { success: true };
8}
9
10// app/SaveForm.tsx (Client Component)
11'use client';
12import { toast } from 'react-toast-kit';
13import { saveData } from './actions';
14
15export default function SaveForm() {
16 const handleSubmit = async (formData: FormData) => {
17 const result = await saveData(formData);
18 if (result.success) {
19 toast.success('Saved!'); // ✓ Called in client component
20 }
21 };
22
23 return <form action={handleSubmit}>...</form>;
24}Fixed Header Offset
If your app has a fixed header, use topOffset to push toasts below it:
// Account for a fixed 64px header
<ToastProvider topOffset={80}>
{children}
</ToastProvider>