inertia-flash-react
v0.1.1
Published
React flash message component for joshdonnell/inertia-flash
Readme
Inertia Flash React
React adapter for joshdonnell/inertia-flash.
This package renders the flash messages sent by the Laravel backend. All message configuration — type, duration, dismissibility, title, and metadata — is controlled server-side via the Laravel package. This adapter handles how those messages look and behave in the browser.
Requirements
- React 18 or 19
- @inertiajs/react ^2.0 or ^3.0
- joshdonnell/inertia-flash installed on your Laravel backend
Installation
npm install inertia-flash-reactImport the styles and add the component to your app layout:
import { FlashMessages } from 'inertia-flash-react';
import 'inertia-flash-react/style.css';
export default function Layout({ children }) {
return (
<>
{children}
<FlashMessages />
</>
);
}That's it. Messages created on the server will appear automatically:
// In your Laravel controller
Flash::success('Profile updated.');
Flash::error('Something went wrong.')->title('Error')->duration(0);How it works
The Laravel package shares flash data with Inertia on every response:
// Server sends via Inertia::flash()
{
"messages": [
{
"id": "550e8400-...",
"type": "success",
"message": "Profile updated.",
"title": null,
"duration": 5000,
"dismissible": true,
"meta": {}
}
]
}This adapter watches page.props.flash.messages and renders each message as a toast. The server controls what gets shown (message content, type, duration, dismissibility). The React adapter controls how it looks (position, styling, icons, animations).
What the Laravel config controls
These are set in your Laravel config/inertia-flash.php and apply to every message by default:
default_duration— auto-dismiss time in milliseconds (0 = persistent)dismissible— whether messages show a close buttonmax_visible— maximum concurrent toastsposition— default position on screen
Individual messages can override duration and dismissibility via the fluent API:
Flash::success('Saved!')->duration(8000)->dismissible(false);What the React adapter controls
- Visual appearance of toasts (colours, spacing, shadows, borders)
- Icon rendering
- Progress bar display
- Position on screen (can override the server default)
Props
| Prop | Type | Default | Description |
| ------------- | ------------------------------------------------------- | ------------- | -------------------------------------------------------------- |
| position | FlashPosition | 'top-right' | Where toasts appear on screen |
| maxVisible | number | 5 | Maximum toasts visible at once |
| icons | boolean | true | Show/hide Lucide icons |
| progress | boolean | true | Show auto-dismiss countdown bar |
| ui | FlashUI | {} | Tailwind class overrides (see Customisation) |
| renderToast | (message, dismiss) => ReactNode | undefined | Replace the entire toast rendering |
| renderIcon | (type, message) => ReactNode | undefined | Replace just the icon |
Position
'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center' | 'bottom-center'<FlashMessages position="bottom-right" />Customisation
Every element of the toast is styled with Tailwind CSS classes and can be overridden via the ui prop. You only need to pass the classes you want to change — they are intelligently merged with the defaults using tailwind-merge, so rounded-none will properly replace the default rounded-xl.
Using Tailwind CSS v4? If you're using custom classes in the
uiprop (e.g. dark mode variants, custom colours), add a@sourcedirective to your app's CSS so Tailwind compiles them:@source "../node_modules/inertia-flash-react/dist/**/*.js";This is only needed if you pass custom Tailwind classes via the
uiprop. The built-in default styles work without it.
The ui prop
<FlashMessages
ui={{
container: {
base: '...', // Outer fixed container
list: '...', // Inner list wrapper (controls toast width)
},
toast: {
base: '...', // Applied to every toast
success: '...', // Applied only to success toasts
error: '...', // Applied only to error toasts
warning: '...', // Applied only to warning toasts
info: '...', // Applied only to info toasts
icon: {
base: '...', // Icon badge (all types)
success: '...', // Icon badge (success only)
error: '...',
warning: '...',
info: '...',
},
content: '...', // Text content wrapper
title: '...', // Title text
message: '...', // Message text
close: '...', // Dismiss button
progress: {
base: '...', // Progress bar (all types)
success: '...', // Progress bar (success only)
error: '...',
warning: '...',
info: '...',
},
},
}}
/>Examples
Dark theme:
<FlashMessages
ui={{
toast: {
base: 'bg-gray-900 border-gray-800 text-gray-100 shadow-2xl',
success: 'border-l-4 border-l-green-500',
error: 'border-l-4 border-l-red-500',
warning: 'border-l-4 border-l-amber-500',
info: 'border-l-4 border-l-blue-500',
icon: {
success: 'bg-green-900 text-green-400',
error: 'bg-red-900 text-red-400',
warning: 'bg-amber-900 text-amber-400',
info: 'bg-blue-900 text-blue-400',
},
message: 'text-gray-400',
},
}}
/>Minimal / flat:
<FlashMessages
ui={{
toast: {
base: 'rounded-none shadow-none border',
icon: { base: 'rounded-none' },
},
}}
/>Wider toasts:
<FlashMessages
ui={{
container: { list: 'w-[480px]' },
}}
/>Default classes
The full default theme is exported as defaultUI if you want to inspect or extend it:
import { defaultUI } from 'inertia-flash-react';
console.log(defaultUI.toast.success);
// → 'bg-green-50 border-green-200 text-green-900'Render props
For full control beyond class overrides, the component accepts render prop functions.
renderToast
Replace the entire toast rendering:
<FlashMessages
renderToast={(message, dismiss) => (
<div className="my-custom-toast">
{message.message}
<button onClick={() => dismiss(message.id)}>Close</button>
</div>
)}
/>renderIcon
Replace just the icon. By default the adapter uses Lucide icons — use this prop to swap in your own icon set:
<FlashMessages
renderIcon={(type, message) => <MyCustomIcon name={type} />}
/>To hide icons entirely:
<FlashMessages icons={false} />Hook
The useFlash hook gives you direct access to the flash message state if you need to build a completely custom UI from scratch:
import { useFlash } from 'inertia-flash-react';
function CustomFlash() {
const { visible, dismiss } = useFlash({ maxVisible: 5 });
return (
<>
{visible.map((msg) => (
<div key={msg.id}>
{msg.title && <strong>{msg.title}</strong>}
<p>{msg.message}</p>
{msg.dismissible && (
<button onClick={() => dismiss(msg.id)}>Dismiss</button>
)}
</div>
))}
</>
);
}Message shape
Each message from the server has the following shape (configured in Laravel):
interface FlashMessage {
id: string; // UUID generated server-side
type: 'success' | 'error' | 'warning' | 'info';
message: string; // Main text (required)
title: string | null; // Optional heading
duration: number; // ms before auto-dismiss (0 = persistent)
dismissible: boolean; // Show close button
meta: Record<string, unknown>; // Arbitrary data from ->meta([...])
}All of these fields are set by the Laravel package — see the backend documentation for the full fluent API.
TypeScript
All types are exported:
import type {
FlashMessage,
FlashType,
FlashPosition,
FlashUI,
FlashToastUI,
FlashContainerUI,
FlashVariantClasses,
} from 'inertia-flash-react';License
MIT License. See LICENSE for more information.
Credits
- Josh Donnell
- Built for Inertia.js + Laravel
