Implementing context menu using react hooks

javascript react reacthooks

Sometimes 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.

  1. When you right click you can get X and Y position of the click using event.pageX and event.pageY
  2. 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.