bx

Context Menu

Displays a menu located at the pointer, triggered by a right click.

Right-click here
tsx
<ContextMenu>
  <ContextMenuTrigger for="row">
    <div>Right-click here</div>
  </ContextMenuTrigger>
  <ContextMenuContent id="row">
    <ContextMenuLabel>Actions</ContextMenuLabel>
    <ContextMenuSeparator />
    <ContextMenuItem>Cut <ContextMenuShortcut>⌘X</ContextMenuShortcut></ContextMenuItem>
    <ContextMenuItem variant="destructive">Delete</ContextMenuItem>
  </ContextMenuContent>
</ContextMenu>

ContextMenu — menu au clic droit (pattern desktop natif). Le trigger enveloppe une zone active ; le clic droit dans cette zone ouvre le menu positionné à la souris.

Composition identique à DropdownMenu : Items, Label, Separator, Shortcut. Sub-menus disponibles (Sub / SubTrigger / SubContent) pour la nav hiérarchique.

Pour les actions "kebab menu" classiques (bouton visible), préférer DropdownMenu. ContextMenu = interaction cachée réservée aux users expérimentés.

Installation

Terminal
$ bext ui add context-menu

Usage

tsx
import { ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuItem, ContextMenuLabel, ContextMenuSeparator, ContextMenuShortcut } from "@bext-stack/ui/primitives"

<ContextMenu>
  <ContextMenuTrigger for="row-ctx">
    <div className="p-8 border rounded-md">Right-click here</div>
  </ContextMenuTrigger>
  <ContextMenuContent id="row-ctx">
    <ContextMenuItem>
      Cut <ContextMenuShortcut>⌘X</ContextMenuShortcut>
    </ContextMenuItem>
    <ContextMenuItem>Copy <ContextMenuShortcut>⌘C</ContextMenuShortcut></ContextMenuItem>
    <ContextMenuSeparator />
    <ContextMenuItem variant="destructive">Delete</ContextMenuItem>
  </ContextMenuContent>
</ContextMenu>

Anatomy

<ContextMenu>
  ├── <ContextMenuTrigger for="ctx-id">
  │   └── <div>Zone active (clic droit ici)</div>
  └── <ContextMenuContent id="ctx-id">
      ├── <ContextMenuLabel>Actions</ContextMenuLabel>
      ├── <ContextMenuItem>Cut <ContextMenuShortcut>⌘X</ContextMenuShortcut></ContextMenuItem>
      ├── <ContextMenuSeparator />
      └── <ContextMenuItem>Delete</ContextMenuItem>

API Reference

ContextMenuTrigger

Prop Type Default Description
for string Match l'id du Content.

ContextMenuContent

Prop Type Default Description
id string Match Trigger.for. Positionné en absolute à la position souris au clic droit.

ContextMenuItem

Prop Type Default Description
variant "default" | "destructive" "default" "destructive" applique text-destructive + focus:bg-destructive/10.
inset boolean pl-8 pour aligner avec les items qui ont un indicateur (checkbox/radio).
href string Si présent, rend .

ContextMenuCheckboxItem

Prop Type Default Description
checked boolean Coche visible à gauche si true.

ContextMenuRadioItem

Prop Type Default Description
checked boolean Point radio visible si true.

ContextMenuLabel

Prop Type Default Description
inset boolean pl-8 pour aligner.

ContextMenuShortcut

Prop Type Default Description
children ReactNode Affiché à droite, muted (ex "⌘X").

ContextMenuSub / SubTrigger / SubContent

Prop Type Default Description
Sub-menu hover-reveal.

Data Attributes

Attributs qu'on peut cibler en CSS custom pour override le style par état.

Attribute On Values Description
data-ui="ctxmenu-trigger" Trigger data-target="#id" L'island écoute contextmenu event sur ces éléments.
data-ui="close" Item Ferme au clic.
data-inset Item / Label présent Reflète la prop inset (pl-8).
data-variant="destructive" Item présent si variant destructive Applique le styling text-destructive.

Keyboard

Key Action
Escape Ferme le menu.
Enter / Space Active l'item focus.

Accessibility

Contextmenu event = pattern desktop non-évident sur mobile ni pour les users clavier-only. Toujours doubler avec un DropdownMenu ou une action visible pour la même fonctionnalité.

Content porte role="menu", items role="menuitem" — à poser à la main en PRISM.

Try it live
Open in play

Edit this component live in the bext playground. The PRISM + signals version is the bext-native idiom — fine-grained reactivity, no virtual DOM.

src/app/page.tsx 2 files · signals · runs in your browser
Pure PRISM + real bext signals — fine-grained, no re-render.