How to handle mouse events in Vue
Mouse event handling enables rich user interactions like clicks, hovers, drag-and-drop, and custom gestures in web applications. As the creator of CoreUI with over 12 years of Vue.js experience since 2014, I’ve implemented complex mouse interactions in enterprise dashboards. Vue provides straightforward event listeners with modifiers to handle mouse events efficiently and declaratively. This approach creates interactive interfaces with tooltips, context menus, draggable elements, and custom behaviors.
Use Vue event listeners to handle mouse events for clicks, hovers, drags, and custom mouse interactions.
<template>
<div>
<!-- Basic mouse events -->
<button
@click='handleClick'
@dblclick='handleDoubleClick'
@mousedown='handleMouseDown'
@mouseup='handleMouseUp'
>
Click me
</button>
<!-- Mouse position tracking -->
<div
@mousemove='trackPosition'
class='tracking-area'
>
Mouse position: {{ mouseX }}, {{ mouseY }}
</div>
<!-- Hover effects -->
<div
@mouseenter='handleEnter'
@mouseleave='handleLeave'
@mouseover='handleOver'
@mouseout='handleOut'
:class="{ hovered: isHovered }"
class='hover-box'
>
{{ isHovered ? 'Hovering!' : 'Hover over me' }}
</div>
<!-- Right click (context menu) -->
<div
@contextmenu.prevent='showContextMenu'
class='context-area'
>
Right click for menu
<div v-if='contextMenuVisible' :style='contextMenuStyle' class='context-menu'>
<ul>
<li @click='handleMenuAction("copy")'>Copy</li>
<li @click='handleMenuAction("paste")'>Paste</li>
<li @click='handleMenuAction("delete")'>Delete</li>
</ul>
</div>
</div>
<!-- Draggable element -->
<div
@mousedown='startDrag'
:style='{ left: dragX + "px", top: dragY + "px" }'
class='draggable'
>
Drag me
</div>
<!-- Mouse button detection -->
<div
@mousedown='handleButton'
class='button-detector'
>
Click with left, middle, or right button
</div>
<!-- Click modifier examples -->
<div>
<button @click.left='handleLeftClick'>Left click only</button>
<button @click.right.prevent='handleRightClick'>Right click only</button>
<button @click.middle='handleMiddleClick'>Middle click only</button>
<button @click.ctrl='handleCtrlClick'>Ctrl + click</button>
<button @click.shift='handleShiftClick'>Shift + click</button>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const mouseX = ref(0)
const mouseY = ref(0)
const isHovered = ref(false)
const contextMenuVisible = ref(false)
const contextMenuStyle = ref({})
const dragX = ref(100)
const dragY = ref(100)
const isDragging = ref(false)
const dragStartX = ref(0)
const dragStartY = ref(0)
const handleClick = (event) => {
console.log('Click:', event)
}
const handleDoubleClick = () => {
console.log('Double click')
}
const handleMouseDown = () => {
console.log('Mouse down')
}
const handleMouseUp = () => {
console.log('Mouse up')
}
const trackPosition = (event) => {
mouseX.value = event.offsetX
mouseY.value = event.offsetY
}
const handleEnter = () => {
isHovered.value = true
console.log('Mouse entered')
}
const handleLeave = () => {
isHovered.value = false
console.log('Mouse left')
}
const handleOver = () => {
console.log('Mouse over')
}
const handleOut = () => {
console.log('Mouse out')
}
const showContextMenu = (event) => {
contextMenuVisible.value = true
contextMenuStyle.value = {
left: event.clientX + 'px',
top: event.clientY + 'px'
}
}
const handleMenuAction = (action) => {
console.log('Menu action:', action)
contextMenuVisible.value = false
}
const startDrag = (event) => {
isDragging.value = true
dragStartX.value = event.clientX - dragX.value
dragStartY.value = event.clientY - dragY.value
}
const handleDragMove = (event) => {
if (isDragging.value) {
dragX.value = event.clientX - dragStartX.value
dragY.value = event.clientY - dragStartY.value
}
}
const stopDrag = () => {
isDragging.value = false
}
const handleButton = (event) => {
if (event.button === 0) console.log('Left button')
if (event.button === 1) console.log('Middle button')
if (event.button === 2) console.log('Right button')
}
const handleLeftClick = () => console.log('Left click only')
const handleRightClick = () => console.log('Right click only')
const handleMiddleClick = () => console.log('Middle click only')
const handleCtrlClick = () => console.log('Ctrl + click')
const handleShiftClick = () => console.log('Shift + click')
onMounted(() => {
window.addEventListener('mousemove', handleDragMove)
window.addEventListener('mouseup', stopDrag)
window.addEventListener('click', () => {
contextMenuVisible.value = false
})
})
onUnmounted(() => {
window.removeEventListener('mousemove', handleDragMove)
window.removeEventListener('mouseup', stopDrag)
})
</script>
<style scoped>
.tracking-area {
width: 100%;
height: 200px;
border: 2px solid #ddd;
padding: 20px;
margin: 10px 0;
}
.hover-box {
padding: 20px;
border: 2px solid #ddd;
margin: 10px 0;
transition: all 0.3s;
}
.hover-box.hovered {
background: #007bff;
color: white;
border-color: #0056b3;
}
.context-area {
padding: 40px;
border: 2px solid #ddd;
margin: 10px 0;
position: relative;
}
.context-menu {
position: fixed;
background: white;
border: 1px solid #ccc;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
z-index: 1000;
}
.context-menu ul {
list-style: none;
padding: 0;
margin: 0;
}
.context-menu li {
padding: 8px 16px;
cursor: pointer;
}
.context-menu li:hover {
background: #f0f0f0;
}
.draggable {
position: fixed;
width: 100px;
height: 100px;
background: #007bff;
color: white;
display: flex;
align-items: center;
justify-content: center;
cursor: move;
user-select: none;
}
.button-detector {
padding: 40px;
border: 2px solid #ddd;
margin: 10px 0;
text-align: center;
}
button {
margin: 5px;
padding: 8px 16px;
}
</style>
Best Practice Note
Use @mouseenter and @mouseleave for hover effects—they don’t bubble like @mouseover/@mouseout. Use .prevent modifier with @contextmenu to prevent default right-click menu. For dragging, attach move and up listeners to window so dragging works outside the element. Use event.button to detect which mouse button was pressed (0=left, 1=middle, 2=right). Clean up global event listeners in onUnmounted to prevent memory leaks. This is how we implement mouse interactions in CoreUI for Vue—providing draggable panels, context menus, tooltips, and custom mouse behaviors for rich, interactive enterprise dashboard experiences.



