HextaUI

Context menu

右クリックまたは長押しで開く操作メニューです。サブメニュー、チェックボックス項目、ラジオ項目に対応し、タッチでは長押しのフィードバックを返します。

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

コンポーネント、HextaUIのテーマトークン、依存するHextaUIコンポーネントを追加します。

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

ファイルリスト

すべての行に専用のメニューを持たせます。開いている行はハイライトされたままで、破壊的な項目は確認のため 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>
  )
}

制御

状態を自分で管理するには、open と onOpenChange を渡します。第 2 引数は、trigger-press、outside-press、escape-key など、変更の理由を示します。closeOnClick={false} の項目は、開いたままにします。

"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>
  )
}

無効

無効な <ContextMenu /> は、その領域をブラウザ自身のメニューに返します。無効な項目は表示されたままですが、キーボードではスキップされます。

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>
  )
}

長押しのフィードバック

タッチスクリーンでは、長押しの後にメニューが開きます。指を押さえている間、領域がわずかに縮み、押下が認識されたことが伝わります。指を動かすとキャンセルされます。オフにするには holdFeedback={false} を設定します。

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>
  )
}

長いコンテンツ

長いラベルは最大 20rem の幅の中で折り返され、高いメニューはビューポートに残った空間の中でスクロールします。

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>
  )
}

ネストしたサブメニュー

サブメニューは、どの階層でも、ホバーまたは矢印キーで開きます。無効なサブメニューのトリガーは開きません。

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>
  )
}

シートの中

メニューは他のオーバーレイの上に重なり、Escape は背後のシートではなく、メニューだけを閉じます。

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>
  )
}

別の要素としてレンダリング

render を使うと、トリガーを figure など任意の要素にしたり、項目をリンクにしたりできます。

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>
  )
}

右から左

メニューはトリガーの方向を読み取るため、サブメニューは左に開き、矢印キーは反転します。

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>
  )
}
キーアクション
↓次の項目をハイライトし、末尾では先頭に回り込みます。
↑前の項目をハイライトし、先頭では末尾に回り込みます。
Home最初の項目をハイライトします。
End最後の項目をハイライトします。
EnterSpaceハイライト中の項目を実行します。チェックボックスとラジオの項目は切り替わり、メニューは開いたままになります。
→ハイライト中のサブメニューを開き、その中に移動します。右から左のレイアウトでは ←。
←現在のサブメニューを閉じ、そのトリガーに戻ります。右から左のレイアウトでは →。
Esc現在のメニューを閉じます。サブメニューでは、そのサブメニューだけが閉じます。
A–Zその文字で始まる次の項目をハイライトします。
  • コンテキストメニューはショートカットです。右クリックや長押しをしない人も多いため、メニュー内のすべてのアクションに、表示されたボタンやドロップダウンメニューなど、別の方法でも到達できるようにしてください。
  • ブラウザは、フォーカスされた要素での Shift F10 や Menu キーでもコンテキストメニューのイベントを発火するため、トリガー内にフォーカス可能な要素があれば、キーボードユーザーも開けます。
  • <ContextMenuShortcut /> のショートカットはラベルのみです。キーのバインドは自分で行ってください。
  • モーションの低減が有効な場合、長押しのフィードバックと項目の点滅はスキップされ、メニューはフェードするだけになります。

Base UI の context menu をベースにしています。各パーツは、ラップしているプリミティブの props と、パーツの state を受け取る関数形式の className を受け付けます。

プロパティ型デフォルト
open
boolean–
defaultOpen
booleanfalse
onOpenChangedetails.reason は、変更の原因を示します。
(open: boolean, details) => void–
onOpenChangeComplete開閉のアニメーションが終わった後に実行されます。
(open: boolean) => void–
disabled代わりに、ブラウザのネイティブメニューを表示します。
booleanfalse
loopFocus矢印キーによる移動を、端で反対側に回り込ませます。
booleantrue
highlightItemOnHover
booleantrue
actionsRefメニューをコードから閉じます。
RefObject<{ close, unmount }>–
プロパティ型デフォルト
holdFeedbackタッチスクリーンで長押ししている間、領域をわずかに縮めます。
booleantrue
render
ReactElement | (props, state) => ReactElement<div>
属性説明
data-slot="context-menu-trigger"CSSでトリガーを指定します。
data-popup-openメニューが開いている間存在します。
data-holding長押しされている間、付与されます。
data-pressedトリガーが押されている間存在します。
プロパティ型デフォルト
sideポインターを基準とした、優先する側。
"top" | "right" | "bottom" | "left" | "inline-start" | "inline-end""bottom"
align
"start" | "center" | "end""start"
sideOffset
number0
alignOffset
number0
collisionPaddingメニューとビューポートの端の間に確保する空間。
number | { top, right, bottom, left }–
collisionAvoidanceメニューがはみ出しそうなときの、反転またはシフトの方法。
CollisionAvoidance–
anchorポインター以外のものを基準に配置します。
Element | VirtualElement | RefObject–
finalFocusメニューを閉じた後にフォーカスが移動する先。
boolean | RefObject | (closeType) => HTMLElement | boolean–
render
ReactElement | (props, state) => ReactElement<div>
属性説明
data-slot="context-menu-content"メニューのポップアップ。
data-open開いている間存在します。
data-starting-styleメニューが表示アニメーションをしている間、付与されます。
data-ending-styleメニューが非表示アニメーションをしている間、付与されます。
data-side衝突の調整後に配置された側。
data-chosen項目がクリックされた後に付与されます。フェードアウトは点滅を待ちます。
--transform-originスケールアニメーションの拡大の起点となる点。
--available-heightビューポートに残っている空間。メニューの高さの上限になります。
プロパティ型デフォルト
variant
"default" | "destructive""default"
insetラベルをインデントして、チェックボックス項目と揃えます。
booleanfalse
onClickクリック、Enter、Space で実行されます。メニューは、短い点滅の後に閉じます。
(event) => void–
closeOnClick
booleantrue
disabled
booleanfalse
labelchildren がプレーンテキストでない場合に、先頭文字検索(typeahead)に使われるテキスト。
string–
render
ReactElement | (props, state) => ReactElement<div>
属性説明
data-slot="context-menu-item"CSSで項目を指定します。
data-variant現在のバリアント。
data-highlightedポインターの下、またはキーボードフォーカスのある項目に付与されます。
data-disabled項目が無効のときに存在します。
data-insetinset が設定されているときに付与されます。
data-chosen点滅している間、クリックされた項目に付与されます。
プロパティ型デフォルト
checked
boolean–
defaultChecked
booleanfalse
onCheckedChange
(checked: boolean, details) => void–
closeOnClick
booleanfalse
inset
booleanfalse
disabled
booleanfalse
render
ReactElement | (props, state) => ReactElement<div>
属性説明
data-slot="context-menu-checkbox-item"CSS でチェックボックス項目を指定します。
data-checkedチェックされているときに付与されます。
data-uncheckedチェックされていないときに付与されます。
data-highlightedポインターの下、またはキーボードフォーカスのある項目に付与されます。
data-disabled項目が無効のときに存在します。
data-insetinset が設定されているときに付与されます。
data-chosen点滅している間、クリックされた項目に付与されます。
プロパティ型デフォルト
value
any–
defaultValue
any–
onValueChange
(value: any, details) => void–
disabled
booleanfalse
プロパティ型デフォルト
value
any–
closeOnClick
booleanfalse
inset
booleanfalse
disabled
booleanfalse
render
ReactElement | (props, state) => ReactElement<div>
属性説明
data-slot="context-menu-radio-item"CSS でラジオ項目を指定します。
data-checked選択されているときに付与されます。
data-highlightedポインターの下、またはキーボードフォーカスのある項目に付与されます。
data-disabled項目が無効のときに存在します。
data-insetinset が設定されているときに付与されます。
data-chosen点滅している間、クリックされた項目に付与されます。
プロパティ型デフォルト
inset
booleanfalse
render
ReactElement | (props, state) => ReactElement<div>

<ContextMenuGroup /> または <ContextMenuRadioGroup /> の内側では、支援技術向けにグループのラベルになります。それ以外では、通常の見出しです。

プロパティ型デフォルト
open
boolean–
defaultOpen
booleanfalse
onOpenChange
(open: boolean, details) => void–
disabled
booleanfalse
closeParentOnEscEscape で、このサブメニューだけでなくメニュー全体を閉じます。
booleanfalse
プロパティ型デフォルト
inset
booleanfalse
openOnHover
booleantrue
delayサブメニューが開くまでのホバー時間(ミリ秒)。
number100
closeDelay
number0
disabled
booleanfalse
render
ReactElement | (props, state) => ReactElement<div>
属性説明
data-slot="context-menu-sub-trigger"CSS でサブメニューのトリガーを指定します。
data-popup-openサブメニューが開いている間、付与されます。
data-highlightedハイライトされている間存在します。
data-disabled無効のときに存在します。
プロパティ型デフォルト
sideデフォルトでは、行末側に向かって開きます。
"top" | "right" | "bottom" | "left" | "inline-start" | "inline-end"–
align
"start" | "center" | "end"–
sideOffset
number0
alignOffset
number-4
collisionPaddingメニューとビューポートの端の間に確保する空間。
number | { top, right, bottom, left }–
collisionAvoidanceメニューがはみ出しそうなときの、反転またはシフトの方法。
CollisionAvoidance–
anchorポインター以外のものを基準に配置します。
Element | VirtualElement | RefObject–
render
ReactElement | (props, state) => ReactElement<div>
属性説明
data-slot="context-menu-sub-content"サブメニューのポップアップ。メニューと同じ state 属性を持ちます。
プロパティ型デフォルト
dir⇧⌘S のようなショートカットを、右から左のメニューでも順序どおりに保ちます。
"ltr" | "rtl""ltr"
属性説明
data-slot="context-menu-shortcut"ショートカットのラベル。

<ContextMenuGroup /> は関連する項目をラベルの下にまとめます。<ContextMenuSeparator /> は区切り線を描画します。どちらも render と className を受け付け、data-slot として context-menu-group と context-menu-separator を持ちます。

使用しているブロック

Context menu の上に構築されるブロック。