7

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

  • Bind to the blur event on my root div element in the control, which doesn't fire at all.
  • I also couldn't find anything about internal component methods which I could override.

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

2
  • Could you provide some code example? Commented Aug 17, 2020 at 9:07
  • @vchan Updated my question accordingly Commented Aug 17, 2020 at 9:15

2 Answers 2

16

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>

Sign up to request clarification or add additional context in comments.

6 Comments

you dont have a component in there
@TheFool something like this? component with custom v-model on it
I think, he wants to propagate blur so i don't see why v-model should be required. Look here what I tried regarding his question but it didn't work. I want to $emit blur and listen to that on the parent. codesandbox.io/s/purple-dew-v87py?file=/src/App.vue
This is what I want, but I don't see, why my blur event is not triggered on a div, while yours is getting fired.
@TheFool i see. divs need tabindex="0" to be focusable. i have said it in my answer aswell at the top
|
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.