Reputation: 8481
In a React app, I use HeadlessUI Dialog to display an item preview from a list. Using keyboard arrows left / right should trigger the display of the next / prev item from the list.
For that, I used the following code:
// Keyboard navigation
// ************************************
useEffect(() => {
const keyDownHandler = (e: KeyboardEvent) => {
// Right arrow =>
if (e.keyCode === 39 && nextItem) {
// Go to next item
goToItem(nextItem);
}
// Left arrow =>
if (e.keyCode === 37 && prevItem) {
// Go to prev item
goToItem(prevItem);
};
}
document.addEventListener('keydown', keyDownHandler);
return () => {
document.removeEventListener('keydown', keyDownHandler);
};
}, [nextItem, prevItem, goToItem]);
Now, the thing is - within the item preview dialog - some other dialogs can also be opened (eg: Share Item Dialog, Report content, etc). This dialogs are opened from different components, so I can not add some open callback to each of them.
If one of these dialogs are opened, I want to disable the keyboard navigation.
The code I've tried is to add the following code to the keydown listener:
// If multiple modals are open, the navigation should be disabled.
// HeadlessUI renders modals within a container element marked with the data-headlessui-portal attribute.
// If multiple data-headlessui-portal elements are present, it indicates that more than one modal is open.
if (document.querySelectorAll('div[data-headlessui-portal]').length > 1) {
return;
}
Is there are approach that I could take?
Upvotes: 0
Views: 169
Reputation: 1810
Create a state that follows active dialog, and set state should update with each dialog. Add isActiveDialog()
inside of useEffect, it should return boolean.
useEffect(() => {
if (isActiveDialog(thisDialog )) {
const keyDownHandler = (e: KeyboardEvent) => {
// Right arrow =>
if (e.keyCode === 39 && nextItem) {
// Go to next item
goToItem(nextItem);
}
// Left arrow =>
if (e.keyCode === 37 && prevItem) {
// Go to prev item
goToItem(prevItem);
};
}
document.addEventListener('keydown', keyDownHandler);
}
return () => {
document.removeEventListener('keydown', keyDownHandler);
};
}, [nextItem, prevItem, goToItem, activeDialog]);
And isActive dialog shoud compare state of dialog with dialog id
const isActiveDialog = () => {
return activeDialog === thisDialog
}
Upvotes: 1