HextaUI

Context menu

Ein Menü mit Aktionen per Rechtsklick oder langem Drücken, mit Untermenüs, Checkbox- und Radio-Einträgen sowie Halte-Feedback auf Touch-Geräten.

Right click here

Last action: Nothing yet

"use client"

import * as React from "react"

import {
  ContextMenu,
  ContextMenuCheckboxItem,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuLabel,
  ContextMenuRadioGroup,
  ContextMenuRadioItem,
  ContextMenuSeparator,
  ContextMenuShortcut,
  ContextMenuSub,
  ContextMenuSubContent,
  ContextMenuSubTrigger,
  ContextMenuTrigger,
} from "@/components/ui/context-menu"

export function ContextMenuDemo() {
  const [bookmarks, setBookmarks] = React.useState(true)
  const [urls, setUrls] = React.useState(false)
  const [person, setPerson] = React.useState("pedro")
  const [last, setLast] = React.useState("Nothing yet")

  return (
    <div className="flex w-full max-w-sm flex-col gap-2">
      <ContextMenu>
        <ContextMenuTrigger className="flex h-40 w-full items-center justify-center rounded-xl border border-dashed text-sm text-muted-foreground">
          Right click here
        </ContextMenuTrigger>
        <ContextMenuContent>
          <ContextMenuItem inset onClick={() => setLast("Back")}>
            Back
            <ContextMenuShortcut>⌘[</ContextMenuShortcut>
          </ContextMenuItem>
          <ContextMenuItem inset disabled>
            Forward
            <ContextMenuShortcut>⌘]</ContextMenuShortcut>
          </ContextMenuItem>
          <ContextMenuItem inset onClick={() => setLast("Reload")}>
            Reload
            <ContextMenuShortcut>⌘R</ContextMenuShortcut>
          </ContextMenuItem>
          <ContextMenuSub>
            <ContextMenuSubTrigger inset>More tools</ContextMenuSubTrigger>
            <ContextMenuSubContent>
              <ContextMenuItem onClick={() => setLast("Save page")}>
                Save page as…
                <ContextMenuShortcut>⇧⌘S</ContextMenuShortcut>
              </ContextMenuItem>
              <ContextMenuItem onClick={() => setLast("Create shortcut")}>
                Create shortcut…
              </ContextMenuItem>
              <ContextMenuItem onClick={() => setLast("Name window")}>
                Name window…
              </ContextMenuItem>
              <ContextMenuSeparator />
              <ContextMenuItem onClick={() => setLast("Developer tools")}>
                Developer tools
              </ContextMenuItem>
            </ContextMenuSubContent>
          </ContextMenuSub>
          <ContextMenuSeparator />
          <ContextMenuCheckboxItem
            checked={bookmarks}
            onCheckedChange={setBookmarks}
          >
            Show bookmarks bar
            <ContextMenuShortcut>⇧⌘B</ContextMenuShortcut>
          </ContextMenuCheckboxItem>
          <ContextMenuCheckboxItem checked={urls} onCheckedChange={setUrls}>
            Show full URLs
          </ContextMenuCheckboxItem>
          <ContextMenuSeparator />
          <ContextMenuRadioGroup value={person} onValueChange={setPerson}>
            <ContextMenuLabel inset>People</ContextMenuLabel>
            <ContextMenuRadioItem value="pedro">
              Pedro Duarte
            </ContextMenuRadioItem>
            <ContextMenuRadioItem value="colm">Colm Tuite</ContextMenuRadioItem>
          </ContextMenuRadioGroup>
        </ContextMenuContent>
      </ContextMenu>
      <p className="text-sm text-muted-foreground">Last action: {last}</p>
    </div>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/context-menu.json

Fügt die Komponente, die HextaUI-Theme-Tokens und alle HextaUI-Komponenten hinzu, von denen sie abhängt.

import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuTrigger,
} from "@/components/ui/context-menu"
<ContextMenu>
  <ContextMenuTrigger>Right click here</ContextMenuTrigger>
  <ContextMenuContent>
    <ContextMenuItem>Profile</ContextMenuItem>
    <ContextMenuItem>Billing</ContextMenuItem>
    <ContextMenuItem variant="destructive">Delete</ContextMenuItem>
  </ContextMenuContent>
</ContextMenu>
ContextMenu
├── ContextMenuTrigger
└── ContextMenuContent
    ├── ContextMenuGroup
    │   ├── ContextMenuLabel
    │   └── ContextMenuItem
    │       └── ContextMenuShortcut
    ├── ContextMenuCheckboxItem
    ├── ContextMenuRadioGroup
    │   └── ContextMenuRadioItem
    ├── ContextMenuSeparator
    └── ContextMenuSub
        ├── ContextMenuSubTrigger
        └── ContextMenuSubContent

Dateiliste

Gib jeder Zeile ihr eigenes Menü. Die geöffnete Zeile behält eine Hervorhebung, und ein destruktiver Eintrag übergibt zur Bestätigung an einen Alert Dialog.

"use client"

import * as React from "react"
import {
  IconCopy,
  IconDownload,
  IconFile,
  IconFolder,
  IconLink,
  IconMail,
  IconPencil,
  IconRefresh,
  IconShare,
  IconStar,
  IconTrash,
} from "@tabler/icons-react"

import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from "@/components/ui/alert-dialog"
import { Button } from "@/components/ui/button"
import {
  ContextMenu,
  ContextMenuCheckboxItem,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuSeparator,
  ContextMenuShortcut,
  ContextMenuSub,
  ContextMenuSubContent,
  ContextMenuSubTrigger,
  ContextMenuTrigger,
} from "@/components/ui/context-menu"

const files = [
  { name: "Quarterly report.pdf", kind: "file" },
  { name: "Brand assets", kind: "folder" },
  { name: "Roadmap 2027.md", kind: "file" },
] as const

function FileRow({
  name,
  kind,
  onDelete,
}: {
  name: string
  kind: "file" | "folder"
  onDelete: () => void
}) {
  const [starred, setStarred] = React.useState(false)
  const Icon = kind === "folder" ? IconFolder : IconFile

  return (
    <ContextMenu>
      <ContextMenuTrigger className="flex items-center gap-3 rounded-lg px-3 py-2 text-sm hover:bg-muted/50 data-popup-open:bg-muted">
        <Icon className="size-4 text-muted-foreground" aria-hidden />
        <span className="min-w-0 flex-1 truncate">{name}</span>
        {starred ? (
          <IconStar
            className="size-4 text-muted-foreground"
            aria-label="Starred"
          />
        ) : null}
      </ContextMenuTrigger>
      <ContextMenuContent>
        <ContextMenuItem>
          <IconPencil />
          Rename…
        </ContextMenuItem>
        <ContextMenuItem>
          <IconCopy />
          Duplicate
          <ContextMenuShortcut>⌘D</ContextMenuShortcut>
        </ContextMenuItem>
        <ContextMenuItem>
          <IconDownload />
          Download
        </ContextMenuItem>
        <ContextMenuCheckboxItem checked={starred} onCheckedChange={setStarred}>
          Starred
        </ContextMenuCheckboxItem>
        <ContextMenuSub>
          <ContextMenuSubTrigger>
            <IconShare />
            Share
          </ContextMenuSubTrigger>
          <ContextMenuSubContent>
            <ContextMenuItem>
              <IconMail />
              Email
            </ContextMenuItem>
            <ContextMenuItem>
              <IconLink />
              Copy link
            </ContextMenuItem>
          </ContextMenuSubContent>
        </ContextMenuSub>
        <ContextMenuSeparator />
        <ContextMenuItem variant="destructive" onClick={onDelete}>
          <IconTrash />
          Delete
          <ContextMenuShortcut>⌘⌫</ContextMenuShortcut>
        </ContextMenuItem>
      </ContextMenuContent>
    </ContextMenu>
  )
}

export function ContextMenuFileList() {
  const [pending, setPending] = React.useState<string | null>(null)
  const [removed, setRemoved] = React.useState<string[]>([])

  return (
    <div className="flex w-full max-w-sm flex-col gap-3">
      <div className="flex flex-col gap-0.5 rounded-xl border p-1">
        {files
          .filter((file) => !removed.includes(file.name))
          .map((file) => (
            <FileRow
              key={file.name}
              name={file.name}
              kind={file.kind}
              onDelete={() => setPending(file.name)}
            />
          ))}
      </div>
      <div>
        <Button variant="outline" size="sm" onClick={() => setRemoved([])}>
          <IconRefresh />
          Restore files
        </Button>
      </div>
      <AlertDialog
        open={pending !== null}
        onOpenChange={(open) => {
          if (!open) {
            setPending(null)
          }
        }}
      >
        <AlertDialogContent size="sm">
          <AlertDialogHeader>
            <AlertDialogTitle>Delete “{pending}”?</AlertDialogTitle>
            <AlertDialogDescription>
              It moves to the trash for 30 days.
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>Cancel</AlertDialogCancel>
            <AlertDialogAction
              variant="destructive"
              onClick={() => {
                if (pending) {
                  setRemoved((value) => [...value, pending])
                }
                setPending(null)
              }}
            >
              Delete
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </div>
  )
}

Kontrolliert

Übergib open und onOpenChange, um den State selbst zu führen. Das zweite Argument nennt den Grund der Änderung, etwa trigger-press, outside-press oder escape-key. Einträge mit closeOnClick={false} halten es offen.

"use client"

import * as React from "react"
import { IconCopy, IconScissors } from "@tabler/icons-react"

import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuTrigger,
} from "@/components/ui/context-menu"

export function ContextMenuControlled() {
  const [open, setOpen] = React.useState(false)
  const [reason, setReason] = React.useState("—")

  return (
    <div className="flex w-full max-w-sm flex-col gap-2">
      <ContextMenu
        open={open}
        onOpenChange={(next, details) => {
          setOpen(next)
          setReason(details.reason)
        }}
      >
        <ContextMenuTrigger className="flex h-40 w-full items-center justify-center rounded-xl border border-dashed text-sm text-muted-foreground">
          Controlled area
        </ContextMenuTrigger>
        <ContextMenuContent>
          <ContextMenuItem>
            <IconScissors />
            Cut
          </ContextMenuItem>
          <ContextMenuItem>
            <IconCopy />
            Copy
          </ContextMenuItem>
          <ContextMenuItem closeOnClick={false}>
            Stays open on click
          </ContextMenuItem>
        </ContextMenuContent>
      </ContextMenu>
      <p className="text-sm text-muted-foreground">
        Open: {String(open)} · last reason: {reason}
      </p>
    </div>
  )
}

Deaktiviert

Ein deaktiviertes <ContextMenu /> gibt den Bereich an das eigene Menü des Browsers zurück. Deaktivierte Einträge bleiben sichtbar, werden aber von der Tastatur übersprungen.

import { IconTrash } from "@tabler/icons-react"

import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuTrigger,
} from "@/components/ui/context-menu"

export function ContextMenuDisabled() {
  return (
    <div className="grid w-full max-w-lg gap-3 sm:grid-cols-2">
      <ContextMenu disabled>
        <ContextMenuTrigger className="flex h-40 w-full items-center justify-center rounded-xl border border-dashed text-sm text-muted-foreground">
          Disabled menu
        </ContextMenuTrigger>
        <ContextMenuContent>
          <ContextMenuItem>Never shown</ContextMenuItem>
        </ContextMenuContent>
      </ContextMenu>
      <ContextMenu>
        <ContextMenuTrigger className="flex h-40 w-full items-center justify-center rounded-xl border border-dashed text-sm text-muted-foreground">
          Disabled items
        </ContextMenuTrigger>
        <ContextMenuContent>
          <ContextMenuItem>Enabled</ContextMenuItem>
          <ContextMenuItem disabled>Disabled item</ContextMenuItem>
          <ContextMenuItem variant="destructive" disabled>
            <IconTrash />
            Disabled destructive
          </ContextMenuItem>
        </ContextMenuContent>
      </ContextMenu>
    </div>
  )
}

Halte-Feedback

Auf Touchscreens öffnet sich das Menü nach einem langen Druck. Solange der Finger gehalten wird, schrumpft der Bereich leicht, damit man merkt, dass der Druck erkannt wurde. Bewegt sich der Finger, wird abgebrochen. Setze holdFeedback={false}, um es abzuschalten.

import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuTrigger,
} from "@/components/ui/context-menu"

export function ContextMenuHoldFeedback() {
  return (
    <div className="grid w-full max-w-lg gap-3 sm:grid-cols-2">
      <ContextMenu>
        <ContextMenuTrigger className="flex h-40 w-full items-center justify-center rounded-xl border border-dashed text-sm text-muted-foreground">
          Press and hold
        </ContextMenuTrigger>
        <ContextMenuContent>
          <ContextMenuItem>Copy</ContextMenuItem>
          <ContextMenuItem>Paste</ContextMenuItem>
        </ContextMenuContent>
      </ContextMenu>
      <ContextMenu>
        <ContextMenuTrigger
          holdFeedback={false}
          className="flex h-40 w-full items-center justify-center rounded-xl border border-dashed text-sm text-muted-foreground"
        >
          No hold feedback
        </ContextMenuTrigger>
        <ContextMenuContent>
          <ContextMenuItem>Copy</ContextMenuItem>
          <ContextMenuItem>Paste</ContextMenuItem>
        </ContextMenuContent>
      </ContextMenu>
    </div>
  )
}

Langer Inhalt

Lange Labels werden innerhalb einer maximalen Breite von 20 rem umgebrochen, und hohe Menüs scrollen im verbleibenden Platz des Viewports.

import { IconFile } from "@tabler/icons-react"

import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuGroup,
  ContextMenuItem,
  ContextMenuLabel,
  ContextMenuShortcut,
  ContextMenuTrigger,
} from "@/components/ui/context-menu"

export function ContextMenuLongContent() {
  return (
    <div className="grid w-full max-w-lg gap-3 sm:grid-cols-2">
      <ContextMenu>
        <ContextMenuTrigger className="flex h-40 w-full items-center justify-center rounded-xl border border-dashed text-sm text-muted-foreground">
          Long labels
        </ContextMenuTrigger>
        <ContextMenuContent>
          <ContextMenuLabel>
            A label that goes on for much longer than any menu label should
          </ContextMenuLabel>
          <ContextMenuItem>
            <IconFile />
            Move to “Supercalifragilisticexpialidocious project archive 2026”
            <ContextMenuShortcut>⌥⌘M</ContextMenuShortcut>
          </ContextMenuItem>
          <ContextMenuItem>
            https://example.com/a/really/long/url/without/any/spaces/at/all/in/it
          </ContextMenuItem>
          <ContextMenuItem>مرحبا بالعالم — mixed العربية text</ContextMenuItem>
          <ContextMenuItem>👩‍👩‍👧‍👦 Family 日本語のテキスト</ContextMenuItem>
          <ContextMenuItem>Short</ContextMenuItem>
        </ContextMenuContent>
      </ContextMenu>
      <ContextMenu>
        <ContextMenuTrigger className="flex h-40 w-full items-center justify-center rounded-xl border border-dashed text-sm text-muted-foreground">
          40 items
        </ContextMenuTrigger>
        <ContextMenuContent>
          <ContextMenuGroup>
            <ContextMenuLabel>Recent</ContextMenuLabel>
            {Array.from({ length: 40 }, (_, index) => (
              <ContextMenuItem key={index}>
                Document {index + 1}
              </ContextMenuItem>
            ))}
          </ContextMenuGroup>
        </ContextMenuContent>
      </ContextMenu>
    </div>
  )
}

Verschachtelte Untermenüs

Untermenüs öffnen sich bei Hover oder mit den Pfeiltasten, in beliebiger Tiefe. Ein deaktivierter Untermenü-Trigger öffnet sich nie.

import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuSub,
  ContextMenuSubContent,
  ContextMenuSubTrigger,
  ContextMenuTrigger,
} from "@/components/ui/context-menu"

export function ContextMenuNested() {
  return (
    <ContextMenu>
      <ContextMenuTrigger className="flex h-40 w-full max-w-sm items-center justify-center rounded-xl border border-dashed text-sm text-muted-foreground">
        Three levels deep
      </ContextMenuTrigger>
      <ContextMenuContent>
        <ContextMenuItem>Open</ContextMenuItem>
        <ContextMenuSub>
          <ContextMenuSubTrigger>Move to</ContextMenuSubTrigger>
          <ContextMenuSubContent>
            <ContextMenuItem>Inbox</ContextMenuItem>
            <ContextMenuSub>
              <ContextMenuSubTrigger>Projects</ContextMenuSubTrigger>
              <ContextMenuSubContent>
                <ContextMenuItem>Acme</ContextMenuItem>
                <ContextMenuSub>
                  <ContextMenuSubTrigger>Archive</ContextMenuSubTrigger>
                  <ContextMenuSubContent>
                    <ContextMenuItem>2024</ContextMenuItem>
                    <ContextMenuItem>2025</ContextMenuItem>
                  </ContextMenuSubContent>
                </ContextMenuSub>
              </ContextMenuSubContent>
            </ContextMenuSub>
            <ContextMenuSub disabled>
              <ContextMenuSubTrigger disabled>Locked</ContextMenuSubTrigger>
              <ContextMenuSubContent>
                <ContextMenuItem>Hidden</ContextMenuItem>
              </ContextMenuSubContent>
            </ContextMenuSub>
          </ContextMenuSubContent>
        </ContextMenuSub>
        <ContextMenuItem variant="destructive">Delete</ContextMenuItem>
      </ContextMenuContent>
    </ContextMenu>
  )
}

In einem Sheet

Das Menü liegt über anderen Overlays, und Escape schließt nur das Menü, nicht das Sheet dahinter.

import { Button } from "@/components/ui/button"
import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuTrigger,
} from "@/components/ui/context-menu"
import {
  Sheet,
  SheetBody,
  SheetContent,
  SheetDescription,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from "@/components/ui/sheet"

export function ContextMenuInSheet() {
  return (
    <Sheet>
      <SheetTrigger render={<Button variant="outline" />}>
        Open sheet
      </SheetTrigger>
      <SheetContent>
        <SheetHeader>
          <SheetTitle>Inside a sheet</SheetTitle>
          <SheetDescription>
            The menu layers above the sheet and Escape closes only the menu.
          </SheetDescription>
        </SheetHeader>
        <SheetBody>
          <ContextMenu>
            <ContextMenuTrigger className="flex h-40 w-full items-center justify-center rounded-xl border border-dashed text-sm text-muted-foreground">
              Right click here
            </ContextMenuTrigger>
            <ContextMenuContent>
              <ContextMenuItem>Copy</ContextMenuItem>
              <ContextMenuItem>Paste</ContextMenuItem>
            </ContextMenuContent>
          </ContextMenu>
        </SheetBody>
      </SheetContent>
    </Sheet>
  )
}

Als anderes Element rendern

Nutze render, um den Trigger zu einem beliebigen Element zu machen, etwa einer Figure, oder um einen Eintrag in einen Link zu verwandeln.

import { IconDownload, IconLink } from "@tabler/icons-react"

import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuTrigger,
} from "@/components/ui/context-menu"

export function ContextMenuRender() {
  return (
    <ContextMenu>
      <ContextMenuTrigger
        render={<figure />}
        className="flex w-full max-w-xs flex-col gap-2 rounded-xl border p-3"
      >
        <div className="h-28 rounded-lg bg-muted" />
        <figcaption className="text-sm text-muted-foreground">
          Trigger rendered as a figure
        </figcaption>
      </ContextMenuTrigger>
      <ContextMenuContent>
        <ContextMenuItem>
          <IconDownload />
          Save image
        </ContextMenuItem>
        <ContextMenuItem render={<a href="#render-as-another-element" />}>
          <IconLink />
          Link item
        </ContextMenuItem>
      </ContextMenuContent>
    </ContextMenu>
  )
}

Rechts nach links

Das Menü liest die Richtung des Triggers, sodass sich Untermenüs nach links öffnen und die Pfeiltasten umkehren.

import { IconArrowLeft, IconArrowRight, IconTrash } from "@tabler/icons-react"

import {
  ContextMenu,
  ContextMenuCheckboxItem,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuSeparator,
  ContextMenuShortcut,
  ContextMenuSub,
  ContextMenuSubContent,
  ContextMenuSubTrigger,
  ContextMenuTrigger,
} from "@/components/ui/context-menu"

export function ContextMenuRtl() {
  return (
    <div dir="rtl" className="w-full max-w-sm">
      <ContextMenu>
        <ContextMenuTrigger className="flex h-40 w-full items-center justify-center rounded-xl border border-dashed text-sm text-muted-foreground">
          انقر بزر الفأرة الأيمن هنا
        </ContextMenuTrigger>
        <ContextMenuContent>
          <ContextMenuItem>
            <IconArrowRight />
            رجوع
            <ContextMenuShortcut>⌘[</ContextMenuShortcut>
          </ContextMenuItem>
          <ContextMenuItem>
            <IconArrowLeft />
            تقدم
          </ContextMenuItem>
          <ContextMenuCheckboxItem defaultChecked>
            إظهار الشريط
          </ContextMenuCheckboxItem>
          <ContextMenuSub>
            <ContextMenuSubTrigger>مشاركة</ContextMenuSubTrigger>
            <ContextMenuSubContent>
              <ContextMenuItem>بريد</ContextMenuItem>
              <ContextMenuItem>نسخ الرابط</ContextMenuItem>
            </ContextMenuSubContent>
          </ContextMenuSub>
          <ContextMenuSeparator />
          <ContextMenuItem variant="destructive">
            <IconTrash />
            حذف
          </ContextMenuItem>
        </ContextMenuContent>
      </ContextMenu>
    </div>
  )
}
TasteAktion
↓Hebt den nächsten Eintrag hervor, am Ende wird umgebrochen.
↑Hebt den vorherigen Eintrag hervor, am Anfang wird umgebrochen.
HomeHebt den ersten Eintrag hervor.
EndHebt den letzten Eintrag hervor.
EnterSpaceFührt den hervorgehobenen Eintrag aus. Checkbox- und Radio-Einträge schalten um und halten das Menü offen.
→Öffnet das hervorgehobene Untermenü und wechselt hinein. ← in Rechts-nach-links-Layouts.
←Schließt das aktuelle Untermenü und kehrt zu seinem Trigger zurück. → in Rechts-nach-links-Layouts.
EscSchließt das aktuelle Menü. In einem Untermenü schließt sich nur dieses Untermenü.
A–ZHebt den nächsten Eintrag hervor, der mit diesem Buchstaben beginnt.
  • Ein Kontextmenü ist eine Abkürzung. Mache jede Aktion darin auch auf anderem Weg erreichbar, etwa über einen sichtbaren Button oder ein Dropdown-Menü, da viele nie rechtsklicken oder lange drücken.
  • Browser lösen das Kontextmenü-Event auch bei Shift+F10 und der Menütaste auf einem fokussierten Element aus, sodass ein fokussierbares Element im Trigger Tastaturnutzern das Öffnen ermöglicht.
  • Kürzel in <ContextMenuShortcut /> sind nur Labels. Binde die Tasten selbst.
  • Bei reduzierter Bewegung entfallen das Halte-Feedback und das Blinken der Einträge, und das Menü blendet nur ein und aus.

Basiert auf dem Base UI Context Menu. Jeder Teil akzeptiert die Props der Primitive, die er umschließt, sowie eine className-Funktion, die den Zustand des Teils erhält.

PropTypStandard
open
boolean–
defaultOpen
booleanfalse
onOpenChangedetails.reason gibt an, was die Änderung ausgelöst hat.
(open: boolean, details) => void–
onOpenChangeCompleteLäuft, nachdem die Öffnen- oder Schließen-Animation beendet ist.
(open: boolean) => void–
disabledZeigt stattdessen das native Menü des Browsers.
booleanfalse
loopFocusDie Pfeiltasten-Navigation an den Enden umbrechen.
booleantrue
highlightItemOnHover
booleantrue
actionsRefDas Menü imperativ schließen.
RefObject<{ close, unmount }>–
PropTypStandard
holdFeedbackVerkleinert den Bereich leicht, solange auf Touchscreens ein langer Druck gehalten wird.
booleantrue
render
ReactElement | (props, state) => ReactElement<div>
AttributBeschreibung
data-slot="context-menu-trigger"Den Trigger in CSS ansprechen.
data-popup-openVorhanden, solange das Menü geöffnet ist.
data-holdingVorhanden, solange ein langer Druck gehalten wird.
data-pressedVorhanden, solange der Trigger gedrückt ist.
PropTypStandard
sideBevorzugte Seite, relativ zum Zeiger.
"top" | "right" | "bottom" | "left" | "inline-start" | "inline-end""bottom"
align
"start" | "center" | "end""start"
sideOffset
number0
alignOffset
number0
collisionPaddingAbstand, der zwischen dem Menü und den Rändern des Viewports bleibt.
number | { top, right, bottom, left }–
collisionAvoidanceWie das Menü umklappt oder sich verschiebt, wenn es überlaufen würde.
CollisionAvoidance–
anchorAn etwas anderem als dem Zeiger positionieren.
Element | VirtualElement | RefObject–
finalFocusWohin der Fokus nach dem Schließen des Menüs geht.
boolean | RefObject | (closeType) => HTMLElement | boolean–
render
ReactElement | (props, state) => ReactElement<div>
AttributBeschreibung
data-slot="context-menu-content"Das Menü-Popup.
data-openVorhanden, solange geöffnet.
data-starting-styleVorhanden, während das Menü eingeblendet wird.
data-ending-styleVorhanden, während das Menü ausgeblendet wird.
data-sideDie Seite, auf der es nach Kollisionen platziert wurde.
data-chosenVorhanden, nachdem ein Eintrag geklickt wurde. Das Ausblenden wartet auf das Blinken.
--transform-originDer Punkt, von dem aus die Skalierungsanimation wächst.
--available-heightVerbleibender Platz im Viewport. Begrenzt die Menühöhe.
PropTypStandard
variant
"default" | "destructive""default"
insetRückt das Label ein, damit es mit Checkbox-Einträgen fluchtet.
booleanfalse
onClickLäuft bei Klick, Enter oder Space. Das Menü schließt sich nach kurzem Blinken.
(event) => void–
closeOnClick
booleantrue
disabled
booleanfalse
labelText für die Typeahead-Suche, wenn die Kinder kein reiner Text sind.
string–
render
ReactElement | (props, state) => ReactElement<div>
AttributBeschreibung
data-slot="context-menu-item"Items in CSS ansprechen.
data-variantDie aktuelle Variante.
data-highlightedVorhanden am Eintrag unter dem Zeiger oder mit Tastaturfokus.
data-disabledVorhanden, wenn das Item deaktiviert ist.
data-insetVorhanden, wenn inset gesetzt ist.
data-chosenVorhanden am geklickten Eintrag, solange er blinkt.
PropTypStandard
checked
boolean–
defaultChecked
booleanfalse
onCheckedChange
(checked: boolean, details) => void–
closeOnClick
booleanfalse
inset
booleanfalse
disabled
booleanfalse
render
ReactElement | (props, state) => ReactElement<div>
AttributBeschreibung
data-slot="context-menu-checkbox-item"Checkbox-Einträge in CSS ansprechen.
data-checkedVorhanden, wenn aktiviert.
data-uncheckedVorhanden, wenn nicht aktiviert.
data-highlightedVorhanden am Eintrag unter dem Zeiger oder mit Tastaturfokus.
data-disabledVorhanden, wenn das Item deaktiviert ist.
data-insetVorhanden, wenn inset gesetzt ist.
data-chosenVorhanden am geklickten Eintrag, solange er blinkt.
PropTypStandard
value
any–
defaultValue
any–
onValueChange
(value: any, details) => void–
disabled
booleanfalse
PropTypStandard
value
any–
closeOnClick
booleanfalse
inset
booleanfalse
disabled
booleanfalse
render
ReactElement | (props, state) => ReactElement<div>
AttributBeschreibung
data-slot="context-menu-radio-item"Radio-Einträge in CSS ansprechen.
data-checkedVorhanden, wenn ausgewählt.
data-highlightedVorhanden am Eintrag unter dem Zeiger oder mit Tastaturfokus.
data-disabledVorhanden, wenn das Item deaktiviert ist.
data-insetVorhanden, wenn inset gesetzt ist.
data-chosenVorhanden am geklickten Eintrag, solange er blinkt.
PropTypStandard
inset
booleanfalse
render
ReactElement | (props, state) => ReactElement<div>

In <ContextMenuGroup /> oder <ContextMenuRadioGroup /> beschriftet es die Gruppe für assistive Technologien. Anderswo ist es eine einfache Überschrift.

PropTypStandard
open
boolean–
defaultOpen
booleanfalse
onOpenChange
(open: boolean, details) => void–
disabled
booleanfalse
closeParentOnEscDas ganze Menü mit Escape schließen, nicht nur dieses Untermenü.
booleanfalse
PropTypStandard
inset
booleanfalse
openOnHover
booleantrue
delayMillisekunden Hover, bevor sich das Untermenü öffnet.
number100
closeDelay
number0
disabled
booleanfalse
render
ReactElement | (props, state) => ReactElement<div>
AttributBeschreibung
data-slot="context-menu-sub-trigger"Untermenü-Trigger in CSS ansprechen.
data-popup-openVorhanden, solange sein Untermenü geöffnet ist.
data-highlightedVorhanden, solange hervorgehoben.
data-disabledVorhanden, wenn deaktiviert.
PropTypStandard
sideÖffnet sich standardmäßig zum Inline-Ende hin.
"top" | "right" | "bottom" | "left" | "inline-start" | "inline-end"–
align
"start" | "center" | "end"–
sideOffset
number0
alignOffset
number-4
collisionPaddingAbstand, der zwischen dem Menü und den Rändern des Viewports bleibt.
number | { top, right, bottom, left }–
collisionAvoidanceWie das Menü umklappt oder sich verschiebt, wenn es überlaufen würde.
CollisionAvoidance–
anchorAn etwas anderem als dem Zeiger positionieren.
Element | VirtualElement | RefObject–
render
ReactElement | (props, state) => ReactElement<div>
AttributBeschreibung
data-slot="context-menu-sub-content"Das Untermenü-Popup. Nimmt dieselben State-Attribute wie das Menü.
PropTypStandard
dirHält Kürzel wie ⇧⌘S in Rechts-nach-links-Menüs in der richtigen Reihenfolge.
"ltr" | "rtl""ltr"
AttributBeschreibung
data-slot="context-menu-shortcut"Das Kürzel-Label.

<ContextMenuGroup /> gruppiert zusammengehörige Einträge unter einem Label. <ContextMenuSeparator /> zeichnet eine Trennlinie. Beide akzeptieren render und className und tragen context-menu-group und context-menu-separator als ihr data-slot.

In Blocks verwendet

Blocks, die auf Context menu aufbauen.