TobiasW
TobiasW

Reputation: 891

Blur event for custom vue component

What I have
A custom DropDown with a filter text input above. The DropDown can be opened independently from the filter text input.

What I want
The intended behavior would be, that the dropdown closes when the filter input loses focus and also when I click with the mouse outside of the DropDown, so that the DropDown loses the focus.

What I tried

Code

  <div @blur="onRootLostFocus">
    ...
  </div>

  ...
  ...
  ...

  onRootLostFocus() {
    console.log('LostFocus');
    this.deactivateSearchPanel();
    this.deactivateSelectionPanel();
  }

Solution

I missed, that a div needs tabindex="0" to be focusable, this fixed my problem

Upvotes: 7

Views: 43437

Answers (2)

PiTheNumber
PiTheNumber

Reputation: 23542

Note there is also tabindex="-1" to make it not reachable via sequential keyboard navigation.

Also consider using a <button> instead because of accessibility concerns.

See https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex

Upvotes: 0

Ilijanovic
Ilijanovic

Reputation: 14904

Something like this?

Answer: You need to set tabindex="0" to make it focusable.

Here an custom dropdown how you could do it:

Vue.component("dropdown", {
   props: ["value"],
   data(){
      return {
         open: false,
         options: ["BMW", "Fiat", "Citroen", "Audi", "Tesla"]
      }
   },
   methods: {
      toggleDropdown() {
         this.open = !this.open;
      },
      closeDropdown(){
         this.open = false;
      },
      selectOption(option) {
         this.$emit("input", option);
      }
   },
   template: `<div class="dropdown">
   <div @blur="closeDropdown" tabindex="0" ref="dropdown" @click="toggleDropdown" class="select">
   {{ value }}
   </div>
   <div class="options" :style="{'max-height': open ? '300px' : '0px'}">
      <div v-for="option in options" @mousedown="selectOption(option)" class="option">
         {{ option }}
      </div>
   </div>
</div>`
})

new Vue({
   el: "#app",
   data: {
      selectedCar: "BMW"
   }
})
.dropdown {
   width: 200px;
   position: relative;
}

.select {
   height: 40px;
   position: absolute;
   left: 0;
   width: 100%;
   background: green;
   display: flex;
   justify-content: center;
   align-items: center;
   color: white;
   cursor: pointer;
}
.option {
   width: 100%;
   height: 40px;
   background: darkgreen;
   color: white;
   display: flex;
   justify-content: center;
   align-items: center;
   cursor: pointer;
}
.option:hover {
   background: green;
}
.options {
   overflow: hidden;
   transition: max-height 200ms;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"> <p>
   {{ selectedCar }}</p>
   <dropdown v-model="selectedCar" />
  
</div>

Upvotes: 16

Related Questions