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
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
- Could you provide some code example? – vchan Commented Aug 17, 2020 at 9:07
- @vchan Updated my question accordingly – TobiasW Commented Aug 17, 2020 at 9:15
2 Answers
Reset to default 16Something 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>
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