JAVASCRIPT
Building a Custom Vue 3 Directive for Click-Outside Detection
Develop a custom Vue 3 directive to easily detect clicks outside a specific DOM element. This pattern is perfect for dismissing modals, dropdowns, or closing popovers with enhanced reusability.
import { DirectiveBinding } from 'vue';
// Define the custom directive
const vClickOutside = {
mounted(el, binding) {
el.__clickOutsideHandler__ = (event) => {
// Check if click is outside the element and not on a child of the element
if (!(el === event.target || el.contains(event.target))) {
binding.value(event);
}
};
document.addEventListener('click', el.__clickOutsideHandler__);
},
unmounted(el) {
document.removeEventListener('click', el.__clickOutsideHandler__);
delete el.__clickOutsideHandler__;
}
};
// Usage in main.js or a plugin (example for main.js):
// import { createApp } from 'vue';
// import App from './App.vue';
// import vClickOutside from './directives/v-click-outside'; // Assuming the directive is in its own file
// const app = createApp(App);
// app.directive('click-outside', vClickOutside);
// app.mount('#app');
// Usage in a Vue component:
// <template>
// <div class="my-dropdown-container" v-click-outside="closeDropdown">
// <button @click="toggleDropdown">Toggle Dropdown</button>
// <div v-if="isOpen" class="dropdown-content">
// Dropdown content here...
// </div>
// </div>
// </template>
// <script setup>
// import { ref } from 'vue';
// const isOpen = ref(false);
// const toggleDropdown = () => {
// isOpen.value = !isOpen.value;
// };
// const closeDropdown = () => {
// if (isOpen.value) {
// isOpen.value = false;
// console.log('Clicked outside! Dropdown closed.');
// }
// };
// </script>
How it works: This code defines a custom Vue 3 directive, `v-click-outside`, enabling components to easily detect when a user clicks anywhere outside the element it's applied to. In `mounted`, it attaches a global click event listener, storing the handler on the element itself (`el.__clickOutsideHandler__`). The handler checks if the click originated outside `el` and its children. In `unmounted`, the listener is properly removed to prevent memory leaks. This directive is ideal for implementing UI patterns like auto-closing dropdowns or modals.