sagalbot / vue-select

Everything you wish the HTML <select> element could do, wrapped up into a lightweight, extensible Vue component.
https://vue-select.org
MIT License
4.63k stars 1.34k forks source link

Prop to close the dropdown when the component looses focus - aka clicking elsewhere on the page #1754

Open runxc1 opened 1 year ago

runxc1 commented 1 year ago

Is your feature request related to a problem? Please describe. Yes this is a usability issue, I have a v-select where both searchable is false as well as clearable. When the user opens the dropdown I want it to close when they select something else on the page.

Describe alternatives you've considered I've looked for a blur event but only find one on the search and as there is no search there is no blur event saying when the component has lost focus.

dpmango commented 1 year ago

Would be really nice to have bugifx for this issue. When you open multiple selects, options collapase. Especially annoying when using multiple selects and close-on-select: false

You can visually make it looks like closed options when they are open

<template>
  <div
    class="select"
    ref="containerRef"
    :class="[
      opened && 'is-opened',
    ]"
    @click="opened = true"
  >
    <vue-select
      @open="opened = true"
      @close="opened = false"
    />
  </div>
</template>

<script setup lang="ts">
import { defineComponent } from 'vue'
import { onClickOutside } from '@vueuse/core'

const containerRef = ref(null)
onClickOutside(containerRef, () => {
  opened.value = false
})

const opened = ref(false)

</script>

<style lang="scss" scoped>
.select {
  position: relative;
  &:not(.is-opened) {
    :deep(.vs__dropdown-menu) {
      opacity: 0 !important;
      pointer-events: none !important;
    }
    :deep(.vs__open-indicator) {
      transform: none;
    }
  }
}
</style>
gregdev commented 1 year ago

I worked around this by leaving searchable as true and then just hiding the search input:

.vs__search {
    opacity: 0;
    pointer-events: none;
}

Not ideal but it works.

faran-tenovos commented 1 year ago

@gregdev approach does work but you loose placeholders as they are not visible what I did as a hack was extended the component added an blur on the input and used that in vue.use for vue app


import Component from 'vue-class-component';
import { VueSelect } from 'vue-select';

@Component({
  name: 'ExtendedVueSelect',
  extends: VueSelect,
  created() {
    this.$on('close', this.onCloseFix);
  },
})
class ExtendedVueSelect extends Vue {
  onCloseFix() {
    // Attempt to access the nested input element and call blur on it for fixing bug
    const inputElement = this.$el.querySelector('input');
    if (inputElement) {
      inputElement.blur();
    }
  }
}

export default {
  install: (v: typeof Vue) => {
    // Register the extended component instead of the original VueSelect
    v.component('VSelect', ExtendedVueSelect);
  },
};