Hi there.
Today I will share the way I built a simple Toast component using Vue3 composables.
Recently, I had to create a project from scratch using Nuxt3 + TailwindCSS. In the middle of it, I needed a simple Toast component to handle some actions. So, after some research, I ended up with this component.
1- Creating the Toast component involves a bit of styling with TailwindCSS classes and custom CSS to control how the Toast appears.
Toast.vue
<script setup lang="ts">
defineProps({
message: {
required: false,
type: String,
},
visibility: {
required: true,
type: Boolean,
},
})
</script>
<template>
<div v-if="visibility"
class="toast z-50 fixed top-4 right-4 flex items-center gap-4 mb-4 text-gray-200 transition-all duration-[3000ms] w-80 overflow-hidden">
<div class="p-3 w-full rounded-tl-none rounded-bl-none">
<div class="flex items-center w-full">
<div class="flex flex-col">
<div class="toast__title text-sm text-green-800">Success</div>
<div class="toast__text text-sm text-green-500">{{ message }}</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.toast {
box-shadow: 0px 4px 14px 0px rgba(0, 0, 0, 0.18);
border-radius: 5px 0px 0px 5px;
border-left: 7px solid #1fac66;
width: 429px;
}
</style>
2- Creating the composable
I've created two functions to handle the logic of the Toast component: one to add the message inside the component and another to reset it. I'm also using the useState composable from Nuxt to keep the variables visibility and messages available.
useToast.ts
export function useToast() {
let visibility = useState('visibility', () => false)
let messages = useState<string[]>('messages', () => [])
function resetMessages() {
messages.value = []
}
function addMessage(message: string) {
if (message) {
messages.value.push(message)
visibility.value = true
setTimeout(() => {
visibility.value = false
resetMessages()
}, 3000)
}
}
return {
messages,
addMessage,
visibility,
}
}
3- In the root component of the project (app.vue in my case), I import the component and the composable to work together. In this example, there are some extras that I added for layout purposes:
app.vue
<script setup lang="ts">
const { messages, visibility } = useToast()
</script>
<template>
<NuxtLayout>
<NuxtPage></NuxtPage>
</NuxtLayout>
<TransitionGroup name="toast">
<Toast v-for="(message, index) in messages" :key="index" :message="message" :index="index"
:visibility="visibility" />
</TransitionGroup>
</template>
<style>
.toast-enter-from,
.toast-leave-to {
opacity: 0;
transform: translateY(-60px);
}
.toast-enter-to,
.toast-leave-from {
opacity: 1;
transform: translateY(0);
}
.toast-enter-active,
.toast-leave-active {
transition: all 0.3s ease;
}
</style>
4- To see it working, you can simply call it from any page or component that you need. Here are two examples:
- To trigger the modal from a page, you can use the following code:
index.vue
<script setup lang="ts">
const { addMessage } = useToast()
function triggerModal() {
addMessage('My Amazing modal from Index.vue')
}
</script>
<template>
<div>
<div>This is my <b>index.vue</b> page</div>
<button @click="triggerModal()">Trigger Modal</button>
</div>
</template>
- To trigger the modal from a random component, you can use the following code:
myRandomComponent.vue
<script setup lang="ts">
const { addMessage } = useToast()
function triggerModal() {
addMessage('My Amazing from component')
}
</script>
<template>
<div>
<div>My test component</div>
<button @click="triggerModal()">Trigger Modal from my Component</button>
</div>
</template>
If you have any suggestions, please let me know. Thank you so much for reading!
Top comments (0)