Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

aareyes00's avatar

Close dropdown when click another element

I have a few dropdown menus that I want to close by clicking outside, another element or focusing an input field.

I'm using this kind of code

<a @click="dropdown()"></a>
 
dropdown() {
 this.openDropdown = !this.openDropdown;
}
0 likes
9 replies
click's avatar
click
Best Answer
Level 35

update: see ellisio's answer for a cleaner solution

If you do not want to add one of the packages mentioned above. You could also try this example (not mine) https://jsfiddle.net/kym2rvyL/1/ it is actually doing the same as one of the packages shown above but it is an easy copy paste:

Your Vue component could look like:

created: function() {
  let self = this;

  window.addEventListener('click', function(e){
    // close dropdown when clicked outside
    if (!self.$el.contains(e.target)){
      self.dropDropdown = false
    } 
  })
}

7 likes
ellisio's avatar

I just came across this looking for a solution to a problem like this. However, the window.addEventListener could result in event pollution on SPAs, would it not? Every time a component is created, it will attach another event listener. Imagine if you have hundreds of tooltips, dropdowns, etc. across your SPA. This would inevitably slow down your application's performance due to all the click events piling up.

Ideally, I would assume you bind a solution to the global App.vue, or hook into the destroy lifecycle event and remove the event listeners to clean up after yourself. Something like this:

export default {
  data() {
    return {
      open: false
    }
  },

  created() {
    window.addEventListener('click', this.close)
  },

  beforeDestroy() {
    window.removeEventListener('click', this.close)
  },

  methods: {
    toggle() {
      this.open = ! this.open
    }

    close(e) {
      if (! this.$el.contains(e.target) {
        this.open = false
      }
    }
  }
}

Live Demo (components/Dropdown.vue): https://codesandbox.io/s/yp7j65270j

9 likes
nrkz's avatar

Better add ref="mydropdown" and instead of this.$el go for a this.$refs.dropdown.contains(e.target)

3 likes
marijnbent's avatar

I've created a Mixin based on the answers of @click and @ellisio, so it's easier to add the logic to multiple components.

// Mixins/CloseOnOutsideClick.js

export default {
    created() {
        window.addEventListener('click', this.clickInElement)
    },
    beforeDestroy() {
        window.removeEventListener('click', this.clickInElement)
    },
    methods: {
        clickInElement(e) {
            if (!this.$el.contains(e.target)) {
                this.close();
            }
        }
    }
};

When adding the mixin to a component, you only have to define a close method!

import closeOnOutsideClickMixin from "../Mixins/closeOnOutsideClick";

export default {
    mixins: [
        closeOnOutsideClickMixin
    ],
    methods: {
        close() {
            this.active = false;
        }
    }
}

Please or to participate in this conversation.