How to Implement a Mouseover or Hover in Vue

In CSS it's pretty easy to change things on hover. We just use the :hover psuedo-class:

.item {
background: blue;
}
.item:hover {
background: green;
}

In Vue it gets a little trickier, because we don't have this functionality built in.

We have to implement most of this ourselves.

But don't worry, it's not that much work.

In this short article you'll learn:

  • How to implement a hover effect in Vue
  • How to show an element on mouseover
  • How to dynamically update classes with a mouseover
  • How to do this even on custom Vue components

Listening to the right events

So, which events do we need to listen to?

We want to know when the mouse is hovering over the element. This can be figured out by keeping track of when the mouse enters the element, and when the mouse leaves the element.

To keep track of when the mouse leaves, we'll use the mouseleave event.

Detecting when the mouse enters can be done with the corresponding mouseenter event, but we won't be using that one.

The reason is that there can be significant performance problems when using mouseenter on deep DOM trees. This is because mouseenter fires a unique event to the entered element, as well as every single ancestor element.

What will we be using instead, you ask?!?

Instead, we will use the mouseover event.

The mouseover event works pretty much the same as mouseenter. The main difference being that mouseover bubbles like most other DOM events. Instead of creating a ton of unique events, there is only one — making it much faster!

Let's hook things up

To hook everything up we will use Vue events to listen for when the mouse enters and leaves, and update our state accordingly.

We will also be using the shorthand of v-on.

Instead of writing v-on:event, we can just write @event.

Here's how we hook it up:

<template>
<div
@mouseover="hover = true"
@mouseleave="hover = false"
/>
</template>
<script setup>
const hover = ref(false);
</script>

In the Options API you'd write the script like this instead:

export default {
data() {
return {
hover: false,
};
}
}

Now the reactive property hover will always reflect if the mouse is hovering over the element or not!

Showing an element when hovering

If you wanted to show an element based on the hover state, you can pair this with a v-if directive:

<template>
<div>
<span
@mouseover="hover = true"
@mouseleave="hover = false"
>
Hover me to show the message!
</span>
<span v-if="hover">This is a secret message.</span>
</div>
</template>
<script setup>
const hover = ref(false);
</script>

Whenever you put your mouse over Hover me to show the message!, the secret message will appear!

Toggling classes when hovering

You can also do a similar thing to toggle classes:

<template>
<div>
<span
@mouseover="hover = true"
@mouseleave="hover = false"
:class="{ active: hover }"
>
Hover me to change the background!
</span>
</div>
</template>
<script setup>
const hover = ref(false);
</script>
<style scoped>
.active {
background: green;
}
</style>

Although that works, it's not the best solution.

For something like this it's better to just use CSS:

<template>
<span>
Hover me to change the background!
</span>
</template>
<style scoped>
span:hover {
background: green;
}
</style>

As you can see, even though we can do it using Vue, we don't need it to achieve this effect.

Hovering over a Vue component

If you have a Vue component that you'd like to implement this behaviour with, you'll have to make a slight modification.

You can't listen to the mouseover and mouseleave events like we were doing before.

We need to modify the component itself to listen to these events, then emit different events that our parent component can listen to.

Parent.vue
1
2
3
4
5
6
7
8
9
10
<template>
<MyComponent
@mouseover="hover = true"
@mouseleave="hover = false"
/>
</template>
<script setup>
const hover = ref(false);
</script>

Modifying our MyComponent to emit these events:

MyComponent.vue
1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div
@mouseover="$emit('mouseover')"
@mouseleave="$emit('mouseleave')"
>
<!-- Rest of the component ... -->
</div>
</template>
<script setup>
defineEmits(['mouseover', 'mouseleave']);
</script>

Conclusion

There you have it!

Achieving a mouseover effect in Vue JS requires only a little bit of code.

Now you can go and do all sorts of things when someone hovers over your Vue app.