How to Create Flash Messaging in Vue 3 & Inertia JS

I was wondering what messaging option to use to provide feedback to the user when they perform an action. I was toying with the idea of either showing a static flash message at the top of the form, which I find is a bit boring and is a bit of a nuisance, or display a message at the bottom right of the screen, which displays for 5 seconds. I feel this is a better solution.

The message to be displayed will either be an error or success message. I have created a component called FlashMessage.vue, and I want to use this component on any other component of the site. Also I wanted the one component to display either a success or error message.

I didn’t want to display a section of code for success and another section for an error. This will cause us to have code duplication. Finally i would like to easily add other type of messages such as info message etc.

Ultimately, I wanted my flash message to look as follows:

The image above is a success message and will appear in the bottom right of the screen.

Lets jump straight into the code. The following is the FlashMessage.vue component html code.

<template>
    <div class="fixed bottom-0 right-0 m-6" v-show="show">
        <div
            :class="{
                'bg-red-200 text-red-900': status === 'error',
                'bg-green-200 text-green-900': status === 'success',
              }"
            class="rounded-lg shadow-md p-6 pr-10"
            style="min-width: 240px"
        >
            <div class="flex items-center">
                {{ message }}
            </div>
            <span class="absolute top-0 bottom-0 right-0 px-4 py-6">
                <svg
                    @click.prevent="hide_message()"
                    :class="{
                        'text-red-900': status === 'error',
                        'text-green-900': status === 'success',
                      }"
                    class="fill-current h-6 w-6"
                    role="button"
                    xmlns="http://www.w3.org/2000/svg"
                    viewBox="0 0 20 20"><title>Close</title>
                    <path
                        d="M14.348 14.849a1.2 1.2 0 0 1-1.697 0L10 11.819l-2.651 3.029a1.2 1.2 0 1 1-1.697-1.697l2.758-3.15-2.759-3.152a1.2 1.2 0 1 1 1.697-1.697L10 8.183l2.651-3.031a1.2 1.2 0 1 1 1.697 1.697l-2.758 3.152 2.758 3.15a1.2 1.2 0 0 1 0 1.698z"
                    />
                </svg>
            </span>
        </div>
    </div>
</template>

The way I dynamically display the success and error styles is with a dynamic class:

:class="{
    'bg-red-200 text-red-900': status === 'error',
    'bg-green-200 text-green-900': status === 'success',
}"

I pass through as a prop the status and the message. The status stores the type of message, either success or error and the message holds the string to be displayed.

Passing data from Laravel to Vue 3 via Inertia JS

Now that I’m using inertiajs which basically glues laravel with Vue JS. Passing data from laravel and vue is very easy and we do this via shared data. We define the data that we want to share in the app/Http/Middleware/HandleInertiaRequests.php. The HandleInertiaRequests middleware provides a “share” method where you can define the data that is automatically shared with each Inertia response.

public function share(Request $request): array
{
    return array_merge(parent::share($request), [

         'flash' => [
            'status' => session('status'),
            'message' => session('message'),
        ],
    ]);
}

After the controller method is executed and the user is redirected, the user feedback is stored in the session via the with() method.

return redirect()->back()->with([
    'status' => 'success',
    'message' => 'We have e-mailed your password reset link!'
]);

The status variable in the session i set to ‘success’ and message is set to ‘We have e-mailed your password reset link!’. Once you’ve shared the data server-side, you’ll then be able to access it within your page components as props. In the vue component, you may access the shared data using $page property. In this case we can access the message, like so:

$page.props.flash.message

How to flash the message on screen

To flash the message on the screen, I don’t actually pass the message to the component as the component has access to the shared data. I can just include the FlashMessage component into any other component as follows:

<FlashMessage />

In the FlashMessage component, I keep an eye on the status. On initial page load the status is set to NULL. As I perform an action, the status is set to either success or error. Around the component HTML I display the v-show attribute which is either true of false. I then check if the status is not equal to null and if it’s not, v-show is set to true and the component is displayed.

let show = ref(usePage().props.value.flash.status !== null)

Accessing the status and message shared data in Vue 3 composition api, I can no longer use $page.props.flash.message. I have to import @inertiajs/inertia-vue3

The javascript setTimeout method is used to hide the message after five seconds. The message can also be hidden by clicking the close button which calls the hide_message method.

<script setup>
    import { ref, watch, computed } from "vue"
    import { usePage } from '@inertiajs/inertia-vue3'

    let show = ref(usePage().props.value.flash.status !== null)

    if (show) {
        setTimeout(() => {
            hide_message()
        }, 5000)
    }

    const hide_message = () => {
        show.value = false
    }
    const show_message = () => {
        show.value = true
    }
</script>

If you have an alternate way to display flash messages on the screen, I would love for you to share and have an open dialogue.

Leave a Reply

Your email address will not be published.