Keyboard navigation triggers next rather than action button
This is something we intended to look at as part of our project but we've run out of time / budget - so I'm raising it, in case anyone else is able to.
I've set up a number of tour steps, most of which have Back and Next buttons but for some steps I've replaced the 'Next' button with a custom action (mostly basic stuff - e.g. click a menu link and then call next).
This works fine when navigating the tour using the mouse but, if you use the keyboard navigation - the right arrow key will always just move the user to the next tour step and never trigger the custom action.
Could there be a way to specify which button should be triggered by the left and right arrow keys? Or, as a bit of a fudge, could the right arrow key trigger the first button on that step which has an action with a class of 'next-button' (and vice versa for the back button)?
@trish1400 this is definitely a known issue. I think the problem is buttons can do anything you want, as you mentioned, so we cannot assume which ones will be next/back etc. I would love to support this, but I don't know of a good way.
Easy to implement.
- In Tour options set
keyboardNavigation: falseto deactivate default navigation. - Add classes
shepherd-left-arrowandshepherd-right-arrowto buttons by setting e.g.
{
action() {return yourFunction()},
classes: 'shepherd-right-arrow',
text: 'Next'
}
- Add custom key listeners.
document.onkeydown = function (e) {
if (Shepherd.activeTour != null){
switch (e.key) {
case 'ArrowUp':
break;
case 'ArrowDown':
break;
case 'ArrowLeft':
$(".shepherd-left-arrow").eq(-1).click();
break;
case 'ArrowRight':
$(".shepherd-right-arrow").eq(-1).click();
break
}
}
};
Note that the function executes only when a tour is active. I added .eq(-1) as there appears to be some kind of bug or logic of a doubled invisible div. The last one however is always the one you would actually click with your mouse. Tested and works well for my use case.
Personally I use this workaround in combination with #1906.
Thanks for sharing @do-me 👍
We should probably make next and previous buttons special cases, instead of allowing custom logic for all buttons. Then we could handle this in the library.
classes: 'shepherd-right-arrow',
Here trying to respond a already good answer in typescript, I'm checking if the element is visible for better handling (using vue but you'll understand no worries)
const shepherdKeyEvents = (e) => {
const clickOnElement = (className: string) => {
const elements = document.querySelectorAll<HTMLElement>(className);
if (
elements.length > 0 &&
elements[elements.length - 1].offsetParent != null
) {
elements[elements.length - 1].click();
}
};
if (this.tour.isActive()) {
switch (e.key) {
case 'ArrowUp':
break;
case 'ArrowDown':
break;
case 'ArrowLeft':
clickOnElement('.shepherd-left-arrow');
break;
case 'ArrowRight':
clickOnElement('.shepherd-right-arrow');
break;
}
}
};
onMounted(() =>
document.addEventListener('keydown', shepherdKeyEvents)
);
onUnmounted(() =>
document.removeEventListener('keydown', shepherdKeyEvents)
);