React + TypeScript: Making a Custom Context Menu

Last updated on September 7, 2021 A Goodman Loading... Post a comment

This article walks you through an end-to-end example of creating a custom context menu in a React app that is written in TypeScript. We’ll use new features of React like hooks and functional components. You won’t see old-fashioned stuff like class-based components or something like that.

Overview

By default, a context menu will show up when you right-click somewhere on a web page with options like “Back”, “Forward”, “Reload”, “Save as…”, “Print…”, etc. However, there might be times when you need a custom context menu with your own defined choices.

React’s event system provides an event named “onContextMenu” that can help us take control of the context menu. To disable the default context menu, use:

event.preventDefault();

In general, a custom context menu needs to satisfy at least the following conditions:

  • Its position must correspond to the position of the mouse pointer.
  • It will disappear when the user left clicks somewhere outside.

Without any further ado, let’s see how its works in action.

The Example

Preview

The Code

1. Create a new project:

npx create-react-app kindacode_ts_react --template typescript

2. Here’s the code in src/App.tsx with explanations:

// App.tsx
// Kindacode.com
import React, { useState } from "react";
import "./App.css";

const App: React.FunctionComponent = () => {
  // Show or hide the custom context menu
  const [isShown, setIsShown] = useState(false);

  // The position of the custom context menu
  const [position, setPosition] = useState({ x: 0, y: 0 });

  // Show the custom context menu
  const showContextMenu = (event: React.MouseEvent<HTMLDivElement>) => {
    // Disable the default context menu
    event.preventDefault();

    setIsShown(false);
    const newPosition = {
      x: event.pageX,
      y: event.pageY,
    };

    setPosition(newPosition);
    setIsShown(true);
  };

  // Hide the custom context menu
  const hideContextMenu = (event: React.MouseEvent<HTMLDivElement>) => {
    setIsShown(false);
  };

  // Do what you want when an option in the context menu is selected
  const [selectedValue, setSelectedValue] = useState<String>();
  const doSomething = (selectedValue: String) => {
    setSelectedValue(selectedValue);
  };

  return (
    <div
      className="container"
      onContextMenu={showContextMenu}
      onClick={hideContextMenu}
    >
      <h2>KindaCode.com</h2>
      {selectedValue && (
        <h1>
          "{selectedValue}" is selected
        </h1>
      )}

      {/* Define the custom context menu */}
      {isShown && (
        <div
          style={{ top: position.y, left: position.x }}
          className="custom-context-menu"
        >
          <div className="option" onClick={() => doSomething("Option 1")}>
            Option #1
          </div>
          <div className="option" onClick={() => doSomething("Option 2")}>
            Option #2
          </div>
          <div className="option" onClick={() => doSomething("Option 3")}>
            Option #3
          </div>
        </div>
      )}
    </div>
  );
};

export default App;

3. Finally, replace all of the default code in your src/App.css with the following:

/* 
App.css
Kindacode.com
 */

.container {
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  z-index: 1;
}

.custom-context-menu {
  position: fixed;
  z-index: 10;
  background: orange;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}

.option {
  cursor: pointer;
  padding: 15px 30px;
}

.option:hover {
  background: yellow;
}

Now run the project and check the result.

Conclusion

We’ve examined a complete example of implementing a custom context menu in a React application that uses TypeScript. If you’d like to learn more about modern React and stuff related to frontend development, take a look at the following articles:

You can also check our React topic page and Next.js topic page for the latest tutorials and examples.

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

Related Articles