Palestinian Flag Solidarity with Palestine. We seek justice and peace, and strongly oppose all forms of injustice and genocide.
Enjoying PHPFlasher? Show your support with a star on GitHub! It helps others discover this tool and motivates us to keep improving it. Thank you

PHPFlasher works seamlessly with Inertia.js, providing a smooth way to display flash notifications in your single-page applications.

Required

PHP Version

v8.2 or higher
Required

Laravel Version

v11.0 or higher
Required

Inertia.js

v1.0 or higher

Using older versions?

If you need to use PHP < v8.2, Laravel < v11.0, or an older Inertia.js version, use PHPFlasher v1 instead. Check out the v1 documentation here .

Installation

To use PHPFlasher with Inertia.js, you'll need to install both the PHP package and JavaScript package.

1. Install the PHP Package

Terminal
PHP Installation
composer require php-flasher/flasher-laravel

2. Add JavaScript Package

Add @flasher/flasher to your package.json:

package.json
{
    "dependencies": {
        "@flasher/flasher": "file:vendor/php-flasher/flasher/Resources"
    }
}

Then, install the JavaScript dependencies:

Terminal
JS Installation
npm install --force

Why the --force flag?

The --force flag is required because we're installing a local package from the filesystem rather than from npm. This is the recommended approach for PHPFlasher to ensure version compatibility.

Usage

To use PHPFlasher with Inertia.js, you need to:

1. Modify Your Middleware

Update your HandleInertiaRequests middleware to share flash notifications:

app/Http/Middleware/HandleInertiaRequests.php
<?php

namespace App\Http\Middleware;

use Illuminate\Http\Request;
use Inertia\Middleware;

class HandleInertiaRequests extends Middleware
{
    /**
     * Defines the props that are shared by default.
     *
     * @see https://inertiajs.com/shared-data
     */
    public function share(Request $request): array
    {
        return array_merge(parent::share($request), [
            // Add flash messages to Inertia shared data
            'messages' => flash()->render('array'),

            // You can include other shared data here
            'auth' => [
                'user' => $request->user(),
            ],
        ]);
    }
}

Pro Tip: Multiple Ways to Share Flash Messages

The render('array') method converts flash messages to a format compatible with JavaScript. You can also use render('json') and parse it in your frontend code.

2. Set Up Your Frontend

Add the code to render notifications in your layout component (example shown with Vue.js):

resources/js/Shared/Layout.vue
<script>
import flasher from "@flasher/flasher";

export default {
  props: {
    messages: Object,
  },
  watch: {
    messages(value) {
      if (value) {
        flasher.render(value);
      }
    }
  },
  mounted() {
    // Display messages on initial load
    if (this.messages) {
      flasher.render(this.messages);
    }
  }
}
</script>

<template>
  <div>
    <header class="bg-white shadow">
      <div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
        <!-- Your navigation -->
        <h1 class="text-xl font-bold text-gray-900">My App</h1>
      </div>
    </header>

    <main>
      <div class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
        <slot />
      </div>
    </main>

    <footer class="bg-white border-t border-gray-200 mt-auto">
      <div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
        <p class="text-center text-gray-500 text-sm">
          &copy; 2025 My Application
        </p>
      </div>
    </footer>
  </div>
</template>

3. Creating Flash Messages

Now you can create flash notifications in your controllers:

app/Http/Controllers/UsersController.php
<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Redirect;
use Inertia\Inertia;

class UsersController extends Controller
{
    /**
     * Display a listing of users.
     */
    public function index()
    {
        return Inertia::render('Users/Index', [
            'users' => User::all()
        ]);
    }

    /**
     * Show the form for creating a new user.
     */
    public function create()
    {
        return Inertia::render('Users/Create');
    }

    /**
     * Store a newly created user in storage.
     */
    public function store(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:8|confirmed',
        ]);

        User::create([
            'name' => $validated['name'],
            'email' => $validated['email'],
            'password' => Hash::make($validated['password']),
        ]);

        // Add a success notification
        flash()->success('User created successfully!');

        // Redirect back, and Inertia will handle passing the flash message
        return Redirect::route('users.index');
    }

    /**
     * Display the specified user.
     */
    public function show(User $user)
    {
        return Inertia::render('Users/Show', [
            'user' => $user
        ]);
    }

    /**
     * Show the form for editing the specified user.
     */
    public function edit(User $user)
    {
        return Inertia::render('Users/Edit', [
            'user' => $user
        ]);
    }

    /**
     * Update the specified user in storage.
     */
    public function update(Request $request, User $user)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users,email,' . $user->id,
        ]);

        $user->update($validated);

        flash()->success('User updated successfully!');

        return Redirect::route('users.index');
    }

    /**
     * Remove the specified user from storage.
     */
    public function destroy(User $user)
    {
        $user->delete();

        flash()->info('User has been deleted.');

        return Redirect::route('users.index');
    }
}

Success Message

flash()->success('Item created successfully!')

Error Message

flash()->error('An error occurred!')

Warning Message

flash()->warning('Please review your submission.')

Info Message

flash()->info('Your session expires in 10 minutes.')

Expert Tips for Inertia.js Integration

  • Keep It Consistent: Use the same notification types for similar actions throughout your application for a predictable user experience.
  • Form Validation: Use flash notifications for general form status, but rely on Inertia's built-in error handling for field-specific validation errors.
  • Watch for Changes: Always use the watch property to detect new notifications after navigation or form submissions.
  • Package Bundling: When using Vite or Webpack, ensure @flasher/flasher is properly included in your bundle.

Examples

CRUD Operations

Here's a complete example of CRUD operations with flash messages:

app/Http/Controllers/ProductController.php
<?php

namespace App\Http\Controllers;

use App\Models\Product;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
use Inertia\Inertia;

class ProductController extends Controller
{
    /**
     * Display a listing of products.
     */
    public function index()
    {
        return Inertia::render('Products/Index', [
            'products' => Product::all()
        ]);
    }

    /**
     * Show the form for creating a new product.
     */
    public function create()
    {
        return Inertia::render('Products/Create');
    }

    /**
     * Store a newly created product in storage.
     */
    public function store(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'price' => 'required|numeric',
            'description' => 'nullable|string|max:1000',
            'category_id' => 'required|exists:categories,id',
        ]);

        Product::create($validated);

        flash()->success('Product created successfully!');

        return Redirect::route('products.index');
    }

    /**
     * Display the specified product.
     */
    public function show(Product $product)
    {
        return Inertia::render('Products/Show', [
            'product' => $product->load('category')
        ]);
    }

    /**
     * Show the form for editing the specified product.
     */
    public function edit(Product $product)
    {
        return Inertia::render('Products/Edit', [
            'product' => $product,
            'categories' => \App\Models\Category::all()
        ]);
    }

    /**
     * Update the specified product in storage.
     */
    public function update(Request $request, Product $product)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'price' => 'required|numeric',
            'description' => 'nullable|string|max:1000',
            'category_id' => 'required|exists:categories,id',
        ]);

        $product->update($validated);

        flash()->success('Product updated successfully!');

        return Redirect::route('products.index');
    }

    /**
     * Remove the specified product from storage.
     */
    public function destroy(Product $product)
    {
        try {
            $product->delete();
            flash()->info('Product has been deleted.');
        } catch (\Exception $e) {
            flash()->error('Cannot delete this product. It may be in use.');
        }

        return Redirect::route('products.index');
    }
}

Best Practice: Error Handling

Always wrap database operations in try-catch blocks and provide user-friendly error messages. This helps users understand what went wrong and what actions they can take to resolve issues.

Authentication Flow

Here's an example of using flash notifications in an authentication flow:

app/Http/Controllers/Auth/AuthController.php
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;

class AuthController extends Controller
{
    /**
     * Show the login form
     */
    public function showLogin()
    {
        return Inertia::render('Auth/Login');
    }

    /**
     * Handle user login request
     */
    public function login(Request $request)
    {
        $credentials = $request->validate([
            'email' => 'required|email',
            'password' => 'required',
        ]);

        if (Auth::attempt($credentials, $request->boolean('remember'))) {
            $request->session()->regenerate();

            flash()->success('Welcome back, ' . Auth::user()->name . '!');

            return Redirect::intended(route('dashboard'));
        }

        throw ValidationException::withMessages([
            'email' => __('auth.failed'),
        ]);
    }

    /**
     * Show registration form
     */
    public function showRegistration()
    {
        return Inertia::render('Auth/Register');
    }

    /**
     * Handle user registration
     */
    public function register(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:8|confirmed',
        ]);

        $user = User::create([
            'name' => $validated['name'],
            'email' => $validated['email'],
            'password' => Hash::make($validated['password']),
        ]);

        Auth::login($user);

        flash()->success('Welcome to our application! Your account has been created.');

        return Redirect::route('dashboard');
    }

    /**
     * Log the user out
     */
    public function logout(Request $request)
    {
        Auth::logout();

        $request->session()->invalidate();
        $request->session()->regenerateToken();

        flash()->info('You have been logged out successfully.');

        return Redirect::route('login');
    }
}

Form Validation

Combine PHPFlasher with Inertia's validation error handling:

app/Http/Controllers/FormController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
use Inertia\Inertia;

class FormController extends Controller
{
    /**
     * Show the contact form
     */
    public function showContactForm()
    {
        return Inertia::render('Contact/Form');
    }

    /**
     * Handle the contact form submission
     */
    public function submitContactForm(Request $request)
    {
        try {
            $validated = $request->validate([
                'name' => 'required|string|max:255',
                'email' => 'required|email',
                'message' => 'required|string|min:10|max:1000',
            ]);

            // Process the form data
            // e.g., send an email, save to database, etc.

            // Show success notification
            flash()->success(
                'Thank you for contacting us! We will get back to you soon.',
                'Message Sent'
            );

            return Redirect::route('contact.thankyou');

        } catch (\Illuminate\Validation\ValidationException $e) {
            // With Inertia, validation errors are automatically passed back
            // Add a generic error message as well
            flash()->error('Please fix the errors in your form.', 'Form Validation Error');

            // With Inertia, this will redirect back with errors
            throw $e;
        } catch (\Exception $e) {
            // Handle other exceptions
            flash()->error(
                'Sorry, we could not process your request. Please try again later.',
                'System Error'
            );

            return Redirect::back();
        }
    }

    /**
     * Show thank you page
     */
    public function showThankYou()
    {
        return Inertia::render('Contact/ThankYou');
    }
}

Corresponding Vue Form Component

resources/js/Pages/Contact/Form.vue
<script setup>
import { useForm } from '@inertiajs/vue3'
import Layout from '@/Layouts/MainLayout.vue'

const form = useForm({
  name: '',
  email: '',
  message: ''
})

const submit = () => {
  form.post(route('contact.submit'))
}
</script>

<template>
  <Layout>
    <div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8">
      <h1 class="text-2xl font-semibold text-gray-900 mb-6">Contact Us</h1>

      <form @submit.prevent="submit" class="space-y-6">
        <div>
          <label for="name" class="block text-sm font-medium text-gray-700">Name</label>
          <input
            id="name"
            v-model="form.name"
            type="text"
            class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-emerald-500 focus:ring focus:ring-emerald-200 focus:ring-opacity-50"
          />
          <div v-if="form.errors.name" class="text-red-500 text-sm mt-1"></div>
        </div>

        <div>
          <label for="email" class="block text-sm font-medium text-gray-700">Email</label>
          <input
            id="email"
            v-model="form.email"
            type="email"
            class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-emerald-500 focus:ring focus:ring-emerald-200 focus:ring-opacity-50"
          />
          <div v-if="form.errors.email" class="text-red-500 text-sm mt-1"></div>
        </div>

        <div>
          <label for="message" class="block text-sm font-medium text-gray-700">Message</label>
          <textarea
            id="message"
            v-model="form.message"
            rows="4"
            class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-emerald-500 focus:ring focus:ring-emerald-200 focus:ring-opacity-50"
          ></textarea>
          <div v-if="form.errors.message" class="text-red-500 text-sm mt-1"></div>
        </div>

        <div class="flex justify-end">
          <button
            type="submit"
            :disabled="form.processing"
            class="inline-flex items-center px-4 py-2 bg-emerald-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-emerald-700 active:bg-emerald-800 focus:outline-none focus:border-emerald-800 focus:ring focus:ring-emerald-300 disabled:opacity-25 transition"
          >
            <span v-if="form.processing">Processing...</span>
            <span v-else>Submit</span>
          </button>
        </div>
      </form>
    </div>
  </Layout>
</template>

Tip: Handling Both Generic and Field-Specific Errors

As shown in the example above, it's often helpful to use PHPFlasher for global form status messages while using Inertia's built-in error handling for field-specific validation errors. This gives users both context-specific and general feedback.

Frontend Framework Integration

Inertia.js works with multiple frontend frameworks. Here's how to integrate PHPFlasher with each:

Vue.js Integration

resources/js/Layouts/AppLayout.vue
<script setup>
import { computed, watch } from 'vue'
import { usePage } from '@inertiajs/vue3'
import flasher from '@flasher/flasher'

// Access shared data from Inertia
const page = usePage()
const messages = computed(() => page.props.messages)

// Watch for changes in flash messages
watch(
  messages,
  (newMessages) => {
    if (newMessages) {
      flasher.render(newMessages)
    }
  },
  { immediate: true }
)
</script>

<template>
  <div class="min-h-screen bg-gray-100">
    <nav class="bg-white border-b border-gray-100">
      <!-- Navigation content -->
    </nav>

    <!-- Page Content -->
    <main>
      <slot />
    </main>

    <footer class="bg-white border-t border-gray-100 mt-auto">
      <!-- Footer content -->
    </footer>
  </div>
</template>

Using flash messages in a Vue component:

resources/js/Pages/Dashboard.vue
<script setup>
import { useForm } from '@inertiajs/vue3'
import AppLayout from '@/Layouts/AppLayout.vue'
import flasher from '@flasher/flasher'

const form = useForm({
  title: '',
  content: ''
})

const submit = () => {
  form.post(route('posts.store'), {
    onSuccess: () => {
      // You can also trigger notifications directly from the frontend
      flasher.success('Post created from the frontend!')

      // Reset the form
      form.reset()
    }
  })
}
</script>

<template>
  <AppLayout>
    <div class="py-12">
      <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
        <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
          <div class="p-6 bg-white border-b border-gray-200">
            <form @submit.prevent="submit">
              <!-- Form fields -->
              <button type="submit" :disabled="form.processing">Create Post</button>
            </form>
          </div>
        </div>
      </div>
    </div>
  </AppLayout>
</template>

Framework-Specific Integration Tips

Vue.js

Use the watch function with immediate: true to ensure flash messages are shown on both initial load and after navigation.

React

With React, use useEffect with messages as a dependency to catch updates to flash messages.

Svelte

Combine onMount and afterUpdate lifecycle functions to ensure flash messages are shown both initially and after updates.

Advanced

Custom Notification Options

Customize your notifications with various options:

CustomOptions.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Inertia\Inertia;

class NotificationController extends Controller
{
    public function showExamples()
    {
        return Inertia::render('Notifications/Examples');
    }

    public function positionExample()
    {
        // Position options
        flash()
            ->option('position', 'bottom-right')
            ->success('Positioned at the bottom-right');

        return back();
    }

    public function timeoutExample()
    {
        // Timeout
        flash()
            ->option('timeout', 8000) // 8 seconds
            ->info('This message stays longer');

        return back();
    }

    public function animationExample()
    {
        // Animation
        flash()
            ->option('showAnimation', 'fadeIn')
            ->option('hideAnimation', 'fadeOut')
            ->success('Custom animations');

        return back();
    }

    public function multipleOptionsExample()
    {
        // Multiple options at once
        flash()
            ->options([
                'position' => 'top-center',
                'timeout' => 3000,
                'closeButton' => false
            ])
            ->success('Multiple options at once');

        return back();
    }
}

Additional Features

Multiple Themes

Choose from 6+ themes including Toastr, SweetAlert, Notyf, Noty and more.

View themes

Internationalization

Support for multiple languages and right-to-left (RTL) layouts.

Learn more

JavaScript API

Access the full JavaScript API for creating notifications directly from the frontend.

Learn more

Ready to enhance your Inertia.js app?

Start using PHPFlasher today and give your users beautiful notifications in minutes!