JAVASCRIPT
Create a `v-click-outside` Custom Directive in Vue 3
Implement a reusable Vue 3 custom directive, `v-click-outside`, to detect clicks occurring outside of a specific element, useful for dropdowns, modals, and popovers.
// directives/vClickOutside.js
const clickOutside = {
mounted(el, binding) {
el.__ClickOutsideHandler__ = (event) => {
if (!(el === event.target || el.contains(event.target))) {
if (typeof binding.value === 'function') {
binding.value(event);
}
}
};
document.addEventListener('click', el.__ClickOutsideHandler__);
},
unmounted(el) {
document.removeEventListener('click', el.__ClickOutsideHandler__);
delete el.__ClickOutsideHandler__;
},
};
export default clickOutside;
// main.js (Registering the directive globally)
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');
// App.vue (Example Usage)
<template>
<div class="page-container">
<h1>`v-click-outside` Directive Example</h1>
<button @click="toggleDropdown">Toggle Dropdown</button>
<div v-if="showDropdown" v-click-outside="onClickOutsideDropdown" class="dropdown-menu">
<p>Dropdown Content</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
<hr>
<button @click="toggleModal">Toggle Modal</button>
<div v-if="showModal" class="modal-backdrop">
<div v-click-outside="onClickOutsideModal" class="modal-content">
<h2>Modal Title</h2>
<p>This is some modal content. Click outside to close it.</p>
<button @click="toggleModal">Close Modal</button>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const showDropdown = ref(false);
const showModal = ref(false);
const toggleDropdown = () => {
showDropdown.value = !showDropdown.value;
};
const onClickOutsideDropdown = () => {
if (showDropdown.value) {
console.log('Clicked outside dropdown!');
showDropdown.value = false;
}
};
const toggleModal = () => {
showModal.value = !showModal.value;
};
const onClickOutsideModal = () => {
if (showModal.value) {
console.log('Clicked outside modal!');
showModal.value = false;
}
};
</script>
<style>
.page-container {
max-width: 800px;
margin: 50px auto;
text-align: center;
position: relative;
}
.dropdown-menu {
border: 1px solid #ccc;
padding: 10px;
margin-top: 10px;
background-color: white;
position: absolute;
left: 50%;
transform: translateX(-50%);
z-index: 10;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.modal-backdrop {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 100;
}
.modal-content {
background-color: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
text-align: left;
}
</style>
How it works: This snippet demonstrates how to create and use a custom Vue 3 directive called `v-click-outside`. This directive is incredibly useful for UI elements like dropdowns, modals, or popovers that need to close when a user clicks anywhere outside of them. The `mounted` hook attaches a global click listener to the document, which checks if the click target is outside the element the directive is bound to. The `unmounted` hook ensures proper cleanup by removing the event listener to prevent memory leaks. The example shows how to apply this directive to both a dropdown and a modal component.