JAVASCRIPT
Implementing a Custom v-ClickOutside Directive in Vue 3
Discover how to create a custom Vue 3 directive like `v-click-outside` to easily detect clicks that occur outside a specified element, perfect for dismissing dropdowns or popovers.
// directives/vClickOutside.js
const clickOutside = {
mounted(el, binding) {
el.__handleClickOutside__ = (event) => {
if (!(el === event.target || el.contains(event.target))) {
binding.value(event)
}
}
document.addEventListener('click', el.__handleClickOutside__)
},
unmounted(el) {
document.removeEventListener('click', el.__handleClickOutside__)
delete el.__handleClickOutside__
}
}
export default clickOutside
// main.js (or a plugin file)
import { createApp } from 'vue'
import App from './App.vue'
import vClickOutside from './directives/vClickOutside'
const app = createApp(App)
app.directive('click-outside', vClickOutside)
app.mount('#app')
// components/DropdownMenu.vue
<template>
<div class="dropdown-wrapper">
<button @click="toggleDropdown">Toggle Dropdown</button>
<div v-if="showDropdown" v-click-outside="hideDropdown" class="dropdown-menu">
<p>Dropdown Item 1</p>
<p>Dropdown Item 2</p>
<p>Dropdown Item 3</p>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const showDropdown = ref(false)
const toggleDropdown = () => {
showDropdown.value = !showDropdown.value
}
const hideDropdown = () => {
showDropdown.value = false
}
</script>
<style scoped>
.dropdown-wrapper {
position: relative;
display: inline-block;
}
.dropdown-menu {
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
padding: 12px 16px;
z-index: 1;
border-radius: 5px;
margin-top: 5px;
}
</style>
How it works: This snippet demonstrates how to create and register a custom `v-click-outside` directive in Vue 3. The directive defines `mounted` and `unmounted` hooks, attaching and detaching a global click event listener respectively. When a click occurs, it checks if the clicked target is outside the element the directive is bound to. If so, it executes the expression provided to the directive (e.g., `hideDropdown`). This is particularly useful for UI components like dropdowns, modals, or popovers that need to be dismissed when the user clicks anywhere else on the page.