V-/Srcv0.1.0beta

// context-menu

Context Menu

A glass menu anchored to the pointer on right-click.

Right-click here
// install
npx shadcn add @vsrc/context-menu

Props

Only the vsrc surface is documented here. Everything else passes through to Radix Context Menu.

// ContextMenuContent

proptypedefaultnotes
glass"subtle" | "regular" | "heavy" | LiquidGlassOptions | falseOptics override for the menu pane. A preset name replaces the tuned values, an object merges over them, `false` disables refraction entirely.

Optics

Forwards `glass` to GlassSurface — engine defaults.

Accessibility

  • Keyboard users open it with the context-menu key or shift+F10 — Radix handles both.
  • Same menu semantics as dropdown: arrows, typeahead, escape.

Source

The exact file the CLI copies into your project — you own it after install.

// registry/vsrc/ui/context-menu.tsx
"use client";

import * as React from "react";
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
import type { GlassPreset, LiquidGlassOptions } from "vsrc/react";

import { GlassSurface } from "@/registry/vsrc/ui/glass-surface";
import { cn } from "@/lib/utils";

const ContextMenu = ContextMenuPrimitive.Root;
const ContextMenuGroup = ContextMenuPrimitive.Group;

function ContextMenuTrigger(props: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) {
  return <ContextMenuPrimitive.Trigger data-slot="context-menu-trigger" {...props} />;
}

function ContextMenuContent({
  className,
  glass,
  ...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Content> & { glass?: LiquidGlassOptions | GlassPreset | false }) {
  return (
    <ContextMenuPrimitive.Portal>
      <GlassSurface asChild glass={glass}>
        <ContextMenuPrimitive.Content
          data-slot="context-menu-content"
          className={cn("animate-glass-in relative z-50 min-w-44 p-1.5 text-foreground outline-none", className)}
          {...props}
        />
      </GlassSurface>
    </ContextMenuPrimitive.Portal>
  );
}

function ContextMenuItem({
  className,
  ...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Item>) {
  return (
    <ContextMenuPrimitive.Item
      data-slot="context-menu-item"
      className={cn(
        "flex cursor-default items-center gap-2 rounded-[calc(var(--glass-radius)-8px)] px-3 py-2 text-sm",
        "outline-none select-none focus:bg-foreground/15",
        "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
        "[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
        className,
      )}
      {...props}
    />
  );
}

function ContextMenuLabel({
  className,
  ...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Label>) {
  return (
    <ContextMenuPrimitive.Label
      data-slot="context-menu-label"
      className={cn("px-3 py-1.5 font-mono text-xs tracking-widest text-muted-foreground uppercase", className)}
      {...props}
    />
  );
}

function ContextMenuSeparator({
  className,
  ...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Separator>) {
  return (
    <ContextMenuPrimitive.Separator
      data-slot="context-menu-separator"
      className={cn("mx-2 my-1 h-px bg-foreground/15", className)}
      {...props}
    />
  );
}

export {
  ContextMenu,
  ContextMenuTrigger,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuLabel,
  ContextMenuSeparator,
  ContextMenuGroup,
};