Skip to content

Click-Outside Directive

The v-click-outside directive is used to detect clicks outside of an element. It is useful for closing dropdowns, modals, and other components that require a click outside to close.

Usage

html
<div v-click-outside="onClickOutside">
  <!-- Your content here -->
</div>
View Code
vue
<template>
  <button
    @click="toggleDropdown"
    class="px-2 py-1 w-full bg-blue-500 text-white rounded-lg max-w-xs"
    type="button"
  >
    Dropdown button
  </button>

  <!-- Dropdown menu -->
  <div
    v-if="showDropdown"
    v-click-outside="closeDropdown"
    class="w-full max-w-xs z-10 bg-white divide-y divide-zinc-100 rounded-lg border dark:border-zinc-700 dark:bg-zinc-700"
  >
    <div class="py-2 text-sm text-zinc-700 dark:text-zinc-200 list-none">
      <li
        class="block px-4 py-2 hover:bg-zinc-100 dark:hover:bg-zinc-600 dark:hover:text-white"
      >
        Dashboard
      </li>

      <li
        class="block px-4 py-2 hover:bg-zinc-100 dark:hover:bg-zinc-600 dark:hover:text-white"
      >
        Settings
      </li>

      <li
        class="block px-4 py-2 hover:bg-zinc-100 dark:hover:bg-zinc-600 dark:hover:text-white"
      >
        Earnings
      </li>
      <li
        class="block px-4 py-2 hover:bg-zinc-100 dark:hover:bg-zinc-600 dark:hover:text-white"
      >
        Sign out
      </li>
    </div>
  </div>
</template>

<script setup>
import { ref } from "vue";

const showDropdown = ref(false);
const toggleDropdown = () => (showDropdown.value = !showDropdown.value);
const closeDropdown = () => (showDropdown.value = false);
</script>

Arguments

The v-click-outside directive does not accept any arguments.

Modifiers

The v-click-outside directive does not accept any modifiers.

Source Code

js
export const vClickOutside = {
  beforeMount(el, binding) {
    el.clickOutsideEvent = function (event) {
      const isTouch = event.type === "touchstart";
      const isClickOutside = !(
        el === event.target || el.contains(event.target)
      );

      if (isTouch || isClickOutside) {
        if (binding.value) {
          let shouldTrigger = true;

          // Check for modifiers
          if (binding.modifiers) {
            if (binding.modifiers.enter && !event.key === "Enter") {
              shouldTrigger = false;
            }
            // Add more modifiers as needed
          }

          // Check for a custom filter function
          if (typeof binding.value === "function" && !binding.value(event)) {
            shouldTrigger = false;
          }

          if (shouldTrigger) {
            binding.value(event);
          }
        }
      }
    };

    // Use capturing phase to handle events before they reach other elements
    document.addEventListener("click", el.clickOutsideEvent, true);
    document.addEventListener("touchstart", el.clickOutsideEvent, true);
  },
  unmounted(el) {
    document.removeEventListener("click", el.clickOutsideEvent, true);
    document.removeEventListener("touchstart", el.clickOutsideEvent, true);
  },
};