Server-Side Toast Notifications for Remix
remix-toast provides utility functions to manage server-side toast notifications within Remix applications, leveraging web standards like `Set-Cookie` for flash messages. It seamlessly integrates with Remix's `loader` and `action` functions and supports React Router v7. The current stable version is 4.0.0, which includes an upgrade to Zod v4. The package appears to have an active release cadence, with frequent updates (minor and patch releases) to address bug fixes, introduce new features like `replaceWithFlash`, and maintain compatibility with new versions of Remix and React Router (e.g., v7.9+ for `react-router`). Key differentiators include its server-side first approach, middleware support for global toast management, and flexible session storage configuration, allowing custom utility creation with `createToastUtilsWithCustomSession`.
Common errors
-
TypeError: (0 , remix_toast_middleware__WEBPACK_IMPORTED_MODULE_2__.getToast) is not a function
cause Incorrect import path for `getToast` or `unstable_toastMiddleware`.fixEnsure `getToast` and `unstable_toastMiddleware` are imported from `remix-toast/middleware` and not directly from `remix-toast`. -
Error: Your Remix application must be using React Router v7 to use remix-toast v2.0.0+
cause Using `remix-toast` v2.0.0 or higher with an incompatible (older) version of `react-router`.fixUpgrade your `react-router` dependency to v7 or higher, or downgrade `remix-toast` to v1.x if you're stuck on an older `react-router` version. -
ReferenceError: require is not defined in ES module scope
cause Attempting to use CommonJS `require()` syntax in an ESM-only environment, or vice-versa.fixUse ESM `import` statements for `remix-toast` as it's designed for modern Remix projects which are typically ESM. If forced to use CJS, configure your build system to transpile or adjust imports accordingly.
Warnings
- breaking The `json*` utilities (e.g., `jsonSuccess`) were renamed to `data*` (e.g., `dataSuccess`) to align with React Router v7 conventions.
- breaking Version 3.0.0 introduced a new 'Middleware mode' for global toast management. This requires changes to `root.tsx` to import `getToast` and `unstable_toastMiddleware` from `remix-toast/middleware` and pass the toast to the client side.
- gotcha The `unstable_toastMiddleware` API was stabilized for `react-router` v7.9+ in version 3.3.0. Using older versions of `react-router` might lead to unexpected behavior or API mismatches when relying on the middleware.
- breaking Version 4.0.0 upgraded the internal dependency `zod` to v4. While this is primarily an internal change, if your application directly relies on `zod` and has specific version constraints, this upgrade might cause conflicts or require you to also upgrade your `zod` dependency.
- gotcha When setting toasts, the `duration` parameter was made optional and can be set to zero. Older versions might not correctly handle a `duration` of zero or might require it to be a positive number.
Install
-
npm install remix-toast -
yarn add remix-toast -
pnpm add remix-toast
Imports
- createToast
const { createToast } = require('remix-toast');import { createToast } from 'remix-toast'; - getToast
import { getToast } from 'remix-toast';import { getToast } from 'remix-toast/middleware'; - unstable_toastMiddleware
import { unstable_toastMiddleware } from 'remix-toast';import { unstable_toastMiddleware } from 'remix-toast/middleware'; - useToast
const useToast = require('remix-toast').useToast;import { useToast } from 'remix-toast';
Quickstart
import { createCookieSessionStorage, redirect } from '@remix-run/node';
import { createToast, getToast, unstable_toastMiddleware } from 'remix-toast/middleware';
import { json } from '@remix-run/react';
import type { ActionFunctionArgs, LoaderFunctionArgs } from '@remix-run/node';
import { useLoaderData } from '@remix-run/react';
// 1. Configure a session storage (replace with your actual session store)
const { getSession, commitSession } = createCookieSessionStorage({
cookie: {
name: '__session',
httpOnly: true,
maxAge: 60 * 60 * 24 * 7, // 1 week
secrets: [process.env.SESSION_SECRET ?? 'super-secret'],
secure: process.env.NODE_ENV === 'production',
},
});
// 2. Setup toast middleware
export const { toast, flash } = createToast(getSession, commitSession);
export const loader = async ({ request }: LoaderFunctionArgs) => {
const { toast, headers } = await getToast(request);
// Simulate fetching some data
const data = { message: 'Welcome back!' };
return json({ data, toast }, { headers });
};
export const action = async ({ request }: ActionFunctionArgs) => {
const formData = await request.formData();
const email = formData.get('email');
if (email === 'error@example.com') {
return await toast.error(redirect('/'), { message: 'Invalid email address.' });
}
return await toast.success(redirect('/'), { message: 'Subscription successful!' });
};
export default function Index() {
const { toast } = useLoaderData<typeof loader>();
return (
<div>
{toast && (
<div style={{ padding: '10px', background: toast.type === 'error' ? 'red' : 'green', color: 'white' }}>
{toast.message}
</div>
)}
<h1>Remix Toast Example</h1>
<form method="post">
<input type="email" name="email" placeholder="Enter email" />
<button type="submit">Subscribe</button>
</form>
</div>
);
}