Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

bwrigley's avatar

Struggling to get flash messages to show in Vue component

Hi There,

I'm brand new to Vue and Intertia, but I'm trying to convert an existing Laravel project into a Laravel/Vue project as a way to put the Intertai/Vue tutorials into action.

I am trying to build on how flash messages are shown in the Intertia documentation but clearly I am doing something wrong, and probably overcomplicating things.

I have a FlashMessage component:

<script setup>
    import { usePage } from '@inertiajs/vue3';
    import { computed } from '@vue/reactivity';
    import { onMounted, ref } from 'vue';

   let show = ref(true);

    const props = defineProps({
            error : {
                type : String,
                default: 'bg-red-800'
            },
            success : {
                type : String,
                default : 'bg-green-800'
            },
            notify : {
                type  :String,
                default : 'bg-blue-500'
            },
            class : {
                type : String,
                default : ''
            }
    });

    let flash = computed(() => {

        if (usePage().props.flash.error) {
            return {
                message : usePage().props.flash.error,
                class : props.class + ' ' + props.error
            }
        }
        else if ( usePage().props.flash.success){
            return {
                message : usePage().props.flash.success,
                class : props.class + ' ' + props.success
            }
        }
        else {
            return {
                message : usePage().props.flash.notify,
                class : props.class + ' ' + props.notify
            }
        }
    });

    onMounted(() => {
        setTimeout(() => {
            show.value = false
        },5000);
    });

</script>



<template>
    <div
        v-show="show"
        class="text-white fixed bottom-2 lg:bottom-10 right-2 lg:right-10 p-2 lg:p-5 rounded-2xl"
        :class="flash.class"
    >
        {{  flash.message }}

    </div>
</template>

which is included in my global layout:

<script setup>

import { Head } from '@inertiajs/vue3';

import Navbar from './Navigation/Navbar.vue';
import FlashMessage from './FlashMessage.vue';

const props = defineProps({
    title: {
      type : String,
      default : null
    }

});

</script>

<template>
    <div class="bottom-0 fixed">*vue</div>

    <Head :title="title ? $page.props.appName + ' - ' + title : $page.props.appName" />

    <Navbar v-if="$page.props.auth.user"/>

    <main class="text-2xl grid place-items-center h-screen bg-gray-900">

      <slot />

    </main>
    <div v-if="!Object.values($page.props.flash).every(v => v===null)">
        <FlashMessage/>
    </div>

</template>

and I have added the relevant lines to the HandInterRequests middleware (correctly I hope)

    public function share(Request $request): array
    {
        return array_merge(parent::share($request), [
            'appName' => config('app.name'),

            'auth.user' => fn () => $request->user()
                ? $request->user()->only('id', 'name', 'email','streak')
                : null,

            'flash' => [
                'success' => fn () => $request->session()->get('success'),
                'error' => fn () => $request->session()->get('error'),
                'notify' => fn () => $request->session()->get('notify')
            ],
        ]);
    }

Then I have a SessionsController where I handle authentication - this was a custom build, not using Breeze or any of the other scaffoldings. I have a store method where I authenticate a user and then forward them to a dashboard, but I want to include a flash message and I'm not sure how:

    public function store()
    {

        $attributes = request()->validate([
            'email' => ['required','email'],
            'password' => ['required']
        ]);

        if (auth()->attempt($attributes)){

            $user = auth()->user();

            if ($user->mostRecentTest()  && ! (Carbon::parse($user->mostRecentTest()->completed_at)->isToday() ||  Carbon::parse($user->mostRecentTest()->completed_at)->isYesterday())){
                $user->streak = 0;
                $user->save();
            }

            return Redirect::route('topic.index')->with('success', 'Welcome back ' . $user->name);

        }

        return back()->withErrors(['email' => 'Your provided credentials cannot be verified.']);

    }

And lastly my TopicController ```index```` method that shows the dashboard:

    public function index()
    {
        return Inertia::render('Topic/Index',[
            'topics' => Auth::check() ? Topic::mine()->orderBy('name')->get() : null
        ]);

    }

This successfully redirects the user to the dashboard but no flash message is shown and using the Vue.js devtools, when I examine the Layout component, all three flash properties are null.

{"success":null,"error":null,"notify":null}

So either I am not setting the flash message or its getting lost in the redirect, or I'm doing something else wrong!

Thanks for any help.

0 likes
1 reply
bwrigley's avatar

I think I have figured out the problem (or part of it), but still not the solution.

When I have a method that does a double redirect I lose the flash message from the session.

Say I have a store method in my SessionController which authenticates a user to and redirects them to my named 'home' route like so:

	return Redirect::route('home')->with('success', 'Welcome back ' . $user->name);

which routes like this:

		Route::get('/', [HomeController::class, 'show'])->name('home');

the show method in HomeController performs some logic and then redirects the user again like so:

		return redirect(route('topics.home'));

in this instance the flash messages in the session are null.

However if in my SessionsController store method I redirect straight to topics.home I do not lose the flash message.

My guess is that this is the double redirect. Is there a way to manage that?

Please or to participate in this conversation.