Implementing context menu using react hooks
javascriptreactreacthooksSometimes you want to override the browsers default context menu in your react app. You can easily do this with a simple custom react hook. Such custom hook should tell you the X and Y position of the context menu and boolean to say whether you should render the component.
Here is a simple implementation of such custom react hook
import { useEffect, useCallback, useState } from 'react';
const useContextMenu = (outerRef) => {
const [xPos, setXPos] = useState('0px');
const [yPos, setYPos] = useState('0px');
const [menu, showMenu] = useState(false);
const handleContextMenu = useCallback(
(event) => {
event.preventDefault();
if (outerRef && outerRef.current.contains(event.target)) {
setXPos(`${event.pageX}px`);
setYPos(`${event.pageY}px`);
showMenu(true);
} else {
showMenu(false);
}
},
[showMenu, outerRef, setXPos, setYPos],
);
const handleClick = useCallback(() => {
showMenu(false);
}, [showMenu]);
useEffect(() => {
document.addEventListener('click', handleClick);
document.addEventListener('contextmenu', handleContextMenu);
return () => {
document.removeEventListener('click', handleClick);
document.removeEventListener('contextmenu', handleContextMenu);
};
}, []);
return { xPos, yPos, menu };
};
export default useContextMenu;
The hook adds two event listener one to intercept the right click and other to intercept the click event.
- When you right click you can get X and Y position of the click using event.pageX and event.pageY
- When you left click you toggle the menu so that it gets hidden
Here is a Menu component that uses that hook
import React from 'react';
import useContextMenu from './useContextMenu';
const Menu = ({ outerRef }) => {
const { xPos, yPos, menu } = useContextMenu(outerRef);
if (menu) {
return (
<ul className="menu" style={{ top: yPos, left: xPos }}>
<li>Item1</li>
<li>Item2</li>
<li>Item3</li>
</ul>
);
}
return <></>;
};
export default Menu;
You render the Menu component based on the boolean and you pass the X and Y position as inline styles.
Here is the demo of the custom hook and here is corresponding source code.
This post is also available on DEV.