Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues with keyboard navigation on KDropdownMenu #818

37 changes: 29 additions & 8 deletions lib/KDropdownMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
data() {
return {
trigger: null,
lastFocusElement: null,
};
},
watch: {
Expand Down Expand Up @@ -145,6 +146,7 @@
},
methods: {
handleOpen() {
this.lastFocusElement = document.activeElement;
this.$nextTick(() => this.$nextTick(() => this.setFocus()));
window.addEventListener('keydown', this.handleOpenMenuNavigation, true);
},
Expand All @@ -160,10 +162,31 @@
focusedElement.classList.contains('ui-popover-focus-redirector') ||
focusedElement.classList.contains('ui-menu-option'))
) {
this.focusOnButton();
if (this.lastFocusElement) {
this.lastFocusElement.focus();
}
}

window.removeEventListener('keyup', this.handleKeyUp, true);
},
getNextFocusableSibling(focusedElement) {
let sibling = focusedElement.nextElementSibling;
while (sibling && !this.isFocusable(sibling)) {
sibling = sibling.nextElementSibling;
}
return sibling;
},
getPreviousFocusableSibling(focusedElement) {
let sibling = focusedElement.previousElementSibling;
while (sibling && !this.isFocusable(sibling)) {
sibling = sibling.previousElementSibling;
}
return sibling;
},
isFocusable(element) {
return element && element.tabIndex >= 0;
},

handleOpenMenuNavigation(event) {
// identify the menu state and length
if (!this.$refs.popover && !this.$refs.popover.$el) {
Expand All @@ -175,19 +198,22 @@
const popoverIsOpen = popover.clientWidth > 0 && popover.clientHeight > 0;
// set current element and its siblings
let focusedElement = document.activeElement;
let sibling = focusedElement.nextElementSibling;
let prevSibling = focusedElement.previousElementSibling;

// manage rotating through the options using arrow keys
// UP arrow: .keyCode is depricated and should used only as a fallback
if ((event.key == 'ArrowUp' || event.keyCode == 38) && popoverIsOpen) {
event.preventDefault();

// Checking if previous sibling is divider and if yes then skip it
const prevSibling = this.getPreviousFocusableSibling(focusedElement);
prevSibling
? this.$nextTick(() => prevSibling.focus())
: this.$nextTick(() => lastChild.focus());
// DOWN arrow
} else if ((event.key == 'ArrowDown' || event.keyCode == 40) && popoverIsOpen) {
event.preventDefault();
//Chekcing if next sibling is divider and skipping it
const sibling = this.getNextFocusableSibling(focusedElement);
sibling ? this.$nextTick(() => sibling.focus()) : this.$nextTick(() => this.setFocus());
// if a TAB key, not an arrow key, close the popover and advance to next item in the tab index
} else if ((event.key == 'Tab' || event.keyCode == 9) && popoverIsOpen) {
Expand All @@ -206,11 +232,6 @@
this.$emit('close');
this.$refs.popover.close();
},
focusOnButton() {
if (this.$refs.button) {
this.$refs.button.$el.focus();
}
},
},
};

Expand Down