Skip to content

Instantly share code, notes, and snippets.

@AnalyzePlatypus
Last active April 27, 2024 05:32
Show Gist options
  • Star 34 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AnalyzePlatypus/22ca31c8f953db92eedadfe930bce31f to your computer and use it in GitHub Desktop.
Save AnalyzePlatypus/22ca31c8f953db92eedadfe930bce31f to your computer and use it in GitHub Desktop.
Vue.js 2.7: Detect clicks outside an element (Close modals, popups, etc.)

Detecting outside clicks in Vue.js

See this StackOverflow thread

First off, include the directive at the end of this gist.

  1. On your open button, make sure to use @click.stop to prevent the open click event from closing your modal.
  2. On your modal, add the v-click-outside directive and points it at a function to call when clicked outside.

Example:

<template>
  <button @click.stop="openPopup” />
  <div v-if="shouldShowModal” v-click-outside="hidePopup” />
</template>

<script>

export default {
  data() {
    return {
      shouldShowModal: false
    };
  },
  methods: {
    showPopup() {
      this.shouldShowModal = true;
    },
    hidePopup() {
      this.shouldShowModal = false;
    }
  },
};
</script>

Directive:

Based on this SO answer

Vue.directive(‘click-outside’,{
  bind: function (el, binding, vnode) {
      el.eventSetDrag = function () {
          el.setAttribute('data-dragging', 'yes');
      }
      el.eventClearDrag = function () {
          el.removeAttribute('data-dragging');
      }
      el.eventOnClick = function (event) {
          var dragging = el.getAttribute('data-dragging');
          // Check that the click was outside the el and its children, and wasn't a drag
          if (!(el == event.target || el.contains(event.target)) && !dragging) {
              // call method provided in attribute value
              vnode.context[binding.expression](event);
          }
      };
      document.addEventListener('touchstart', el.eventClearDrag);
      document.addEventListener('touchmove', el.eventSetDrag);
      document.addEventListener('click', el.eventOnClick);
      document.addEventListener('touchend', el.eventOnClick);
  }, unbind: function (el) {
      document.removeEventListener('touchstart', el.eventClearDrag);
      document.removeEventListener('touchmove', el.eventSetDrag);
      document.removeEventListener('click', el.eventOnClick);
      document.removeEventListener('touchend', el.eventOnClick);
      el.removeAttribute('data-dragging');
  },
});
@shershen
Copy link

Thanks you! 👍 🎉 😎

@dbramwell
Copy link

dbramwell commented Jun 11, 2021

Update for Vue 3:

{
  beforeMount(el, binding, vnode) {
      el.eventSetDrag = function () {
          el.setAttribute('data-dragging', 'yes');
      }
      el.eventClearDrag = function () {
          el.removeAttribute('data-dragging');
      }
      el.eventOnClick = function (event) {
          var dragging = el.getAttribute('data-dragging');
          // Check that the click was outside the el and its children, and wasn't a drag
          if (!(el == event.target || el.contains(event.target)) && !dragging) {
              // call method provided in attribute value
              binding.value(event);
          }
      };
      document.addEventListener('touchstart', el.eventClearDrag);
      document.addEventListener('touchmove', el.eventSetDrag);
      document.addEventListener('click', el.eventOnClick);
      document.addEventListener('touchend', el.eventOnClick);
  },
  unmounted(el) {
      document.removeEventListener('touchstart', el.eventClearDrag);
      document.removeEventListener('touchmove', el.eventSetDrag);
      document.removeEventListener('click', el.eventOnClick);
      document.removeEventListener('touchend', el.eventOnClick);
      el.removeAttribute('data-dragging');
  }
}

@mrtrimble
Copy link

Thanks! This worked perfectly!

@camrobjones
Copy link

"On your open button, make sure to use @click.stop to prevent the open click event from closing your modal." Thanks so much, this was my issue with another solution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment