Devie UI
Version: 2026-02-14
Right click here

The ContextMenu component extends Base UI's ContextMenu with polished default styles. It displays a menu of contextual actions triggered by right-clicking (or long-pressing on touch devices) on an element. We added custom subcomponents: SubmenuChevron for submenu trigger icons, and Shortcut for displaying keyboard shortcuts alongside menu items.

Installation

Here is the component implementation code that you can copy to your project:

// https://devie-ui.com/components/context-menu
// https://base-ui.com/react/components/context-menu
 
import { ContextMenu as BaseContextMenu } from "@base-ui/react/context-menu";
import clsx from "clsx";
import { Check, ChevronRight, Circle } from "lucide-react";
import type React from "react";
import styles from "./ContextMenu.module.scss";
 
const Root = BaseContextMenu.Root;
 
function Trigger({ className, ...props }: BaseContextMenu.Trigger.Props) {
  return (
    <BaseContextMenu.Trigger
      className={clsx(styles.trigger, className)}
      {...props}
    />
  );
}
 
const Portal = BaseContextMenu.Portal;
 
const Backdrop = BaseContextMenu.Backdrop;
 
function Positioner({ className, ...props }: BaseContextMenu.Positioner.Props) {
  return (
    <BaseContextMenu.Positioner
      className={clsx(styles.positioner, className)}
      {...props}
    />
  );
}
 
function Popup({ className, ...props }: BaseContextMenu.Popup.Props) {
  return (
    <BaseContextMenu.Popup
      className={clsx(styles.popup, className)}
      {...props}
    />
  );
}
 
function Arrow({ className, ...props }: BaseContextMenu.Arrow.Props) {
  return (
    <BaseContextMenu.Arrow
      className={clsx(styles.arrow, className)}
      {...props}
    />
  );
}
 
function Item({ className, ...props }: BaseContextMenu.Item.Props) {
  return (
    <BaseContextMenu.Item className={clsx(styles.item, className)} {...props} />
  );
}
 
function LinkItem({ className, ...props }: BaseContextMenu.LinkItem.Props) {
  return (
    <BaseContextMenu.LinkItem
      className={clsx(styles.item, className)}
      {...props}
    />
  );
}
 
function Separator({ className, ...props }: BaseContextMenu.Separator.Props) {
  return (
    <BaseContextMenu.Separator
      className={clsx(styles.separator, className)}
      {...props}
    />
  );
}
 
function Group({ className, ...props }: BaseContextMenu.Group.Props) {
  return (
    <BaseContextMenu.Group
      className={clsx(styles.group, className)}
      {...props}
    />
  );
}
 
function GroupLabel({ className, ...props }: BaseContextMenu.GroupLabel.Props) {
  return (
    <BaseContextMenu.GroupLabel
      className={clsx(styles.groupLabel, className)}
      {...props}
    />
  );
}
 
function RadioGroup({ className, ...props }: BaseContextMenu.RadioGroup.Props) {
  return (
    <BaseContextMenu.RadioGroup
      className={clsx(styles.radioGroup, className)}
      {...props}
    />
  );
}
 
function RadioItem({ className, ...props }: BaseContextMenu.RadioItem.Props) {
  return (
    <BaseContextMenu.RadioItem
      className={clsx(styles.item, styles.radioItem, className)}
      {...props}
    />
  );
}
 
function RadioItemIndicator({
  className,
  children,
  ...props
}: BaseContextMenu.RadioItemIndicator.Props) {
  return (
    <BaseContextMenu.RadioItemIndicator
      className={clsx(styles.itemIndicator, className)}
      {...props}
    >
      {children || <Circle size={8} fill="currentColor" />}
    </BaseContextMenu.RadioItemIndicator>
  );
}
 
function CheckboxItem({
  className,
  ...props
}: BaseContextMenu.CheckboxItem.Props) {
  return (
    <BaseContextMenu.CheckboxItem
      className={clsx(styles.item, styles.checkboxItem, className)}
      {...props}
    />
  );
}
 
function CheckboxItemIndicator({
  className,
  children,
  ...props
}: BaseContextMenu.CheckboxItemIndicator.Props) {
  return (
    <BaseContextMenu.CheckboxItemIndicator
      className={clsx(styles.itemIndicator, className)}
      {...props}
    >
      {children || <Check size={16} strokeWidth={1.5} />}
    </BaseContextMenu.CheckboxItemIndicator>
  );
}
 
const SubmenuRoot = BaseContextMenu.SubmenuRoot;
 
function SubmenuTrigger({
  className,
  ...props
}: BaseContextMenu.SubmenuTrigger.Props) {
  return (
    <BaseContextMenu.SubmenuTrigger
      className={clsx(styles.item, styles.submenuTrigger, className)}
      {...props}
    />
  );
}
 
interface SubmenuChevronProps extends React.HTMLAttributes<HTMLDivElement> {
  className?: string;
  children?: React.ReactNode;
}
 
function SubmenuChevron({
  className,
  children,
  ...props
}: SubmenuChevronProps) {
  return (
    <div className={clsx(styles.submenuChevron, className)} {...props}>
      {children || <ChevronRight size={16} />}
    </div>
  );
}
 
interface ShortcutProps extends React.HTMLAttributes<HTMLElement> {
  className?: string;
}
 
function Shortcut({ className, ...props }: ShortcutProps) {
  return <kbd className={clsx(styles.shortcut, className)} {...props} />;
}
 
const ContextMenu = {
  Root,
  Trigger,
  Portal,
  Backdrop,
  Positioner,
  Popup,
  Arrow,
  Item,
  LinkItem,
  Separator,
  Group,
  GroupLabel,
  RadioGroup,
  RadioItem,
  RadioItemIndicator,
  CheckboxItem,
  CheckboxItemIndicator,
  SubmenuRoot,
  SubmenuTrigger,
  SubmenuChevron,
  Shortcut,
};
 
export default ContextMenu;

Use Cases

Simple context menu

A basic context menu with items and a separator. Use the disabled prop to disable specific items.

Right click here

Use LinkItem for context menu items that navigate to a URL. It renders an <a> element and supports the closeOnClick prop to close the menu when clicked.

Right click here

With keyboard shortcuts

Use Shortcut to display keyboard shortcut hints alongside menu items.

Right click here

Use SubmenuRoot, SubmenuTrigger, and SubmenuChevron to create nested menus.

Right click here

With groups

Use Group and GroupLabel to organize items into labeled sections.

Right click here

With checkbox items

Use CheckboxItem and CheckboxItemIndicator for toggleable options within the menu.

Right click here

With radio items

Use RadioGroup, RadioItem, and RadioItemIndicator for single-selection options.

Right click here