You need three things for this
NOTE: Options Api gist here
1- A compontent ref like this:
<template>
<div
ref="componentRef"
class="general-style"
>
</div>
</template>
<script setup>
import { ref } from 'vue'
const componentRef = ref()
</script>
2- The next composable:
import {onBeforeUnmount, onMounted} from 'vue'
export default function useDetectOutsideClick(component, callback) {
if (!component) return
const listener = (event) => {
if (event.target !== component.value && event.composedPath().includes(component.value)) {
return
}
if (typeof callback === 'function') {
callback()
}
}
onMounted(() => { window.addEventListener('click', listener) })
onBeforeUnmount(() => {window.removeEventListener('click', listener)})
return {listener}
}
3- Use within your component and send the ref as composable param:
<template>
<div
ref="componentRef"
class="general-style"
>
</div>
</template>
<script setup>
import { ref } from 'vue'
import useDetectOutsideClick from '/useDetectOutsideClick'
const componentRef = ref()
const exampleComposableText = ref('hello')
useDetectOutsideClick(componentRef, () => {
exampleComposableText.value = 'edit hello'
})
</script>
Summary: Just declare a ref, point the ref to the template element and send it to the composable as first parameter. The second parameter of the composable is the callback what do you want to execute when clicked out.
Happy Code!
Top comments (3)
On popup div, i placed a ref, to close it when clicked outside, and there is a button for opening a popup, upon clicking button it treats it the outside element and goes to callback function, where popup close logic is implemented and in result popup never opens, please suggest to ignore button click
how to handle it for when i have more then one comp i mean i use it for dropdown how to know which one to close ?
Why not write a custom directive?