संदर्भ मेनू
फ़ाइल पंक्तियों, कैनवस और डेटा ग्रिड्स के लिए राइट-क्लिक मेनू — संदर्भगत क्रियाएँ, नियोब्रूटलिस्ट शैली के बॉर्डर-और-छाया प्रभाव के साथ।
import {
ContextMenu,
ContextMenuCheckboxItem,कॉन्टेक्स्ट मेनू राइट-क्लिक (या टच पर long-press) पर पॉइंटर पर एक्शन की फ़्लोटिंग सूची खोलता है — सबमेनू, चेकबॉक्स और रेडियो आइटम, और कीबोर्ड शॉर्टकट के साथ। यह Base UI Context Menu कंपोनेंट पर बना है और नियोब्रूटलिस्ट रेसिपी के अनुसार स्टाइल किया गया है: मोटे बॉर्डर, कठोर छायाएँ और बोल्ड टाइपोग्राफ़ी।
इसे इन स्थितियों में चुनें:
- फ़ाइल और पंक्ति एक्शन — फ़ाइल-मैनेजर एंट्री या टेबल पंक्ति पर rename, duplicate, delete; हर पंक्ति पर बटन की भीड़ के बिना।
- कैनवास सतह — व्हाइटबोर्ड, डिज़ाइन टूल, एडिटर जहाँ उपलब्ध एक्शन क्लिक की जगह पर निर्भर करें।
- डेटा ग्रिड — कॉपी वैल्यू, फ़िल्टर बाय, पिन कॉलम जैसे प्रति-सेल ऑपरेशन, डेटा के पास।
इंस्टॉलेशन#
pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/context-menu.jsonnpx shadcn@latest add https://neobrutalism.com/r/base/context-menu.jsonyarn dlx shadcn@latest add https://neobrutalism.com/r/base/context-menu.jsonbunx --bun shadcn@latest add https://neobrutalism.com/r/base/context-menu.json
निम्नलिखित डिपेंडेंसी इंस्टॉल करें:
pnpm add @base-ui/reactnpm install @base-ui/reactyarn add @base-ui/reactbun add @base-ui/react
निम्नलिखित कोड को अपने प्रोजेक्ट में कॉपी और पेस्ट करें.
"use client"
import * as React from "react"
import { CheckIcon, ChevronRightIcon } from "lucide-react"
import { ContextMenu as ContextMenuPrimitive } from "radix-ui"
import { cn } from "@/lib/utils"
function ContextMenu({
...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Root>) {
return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />
}
function ContextMenuTrigger({
className,
...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Trigger>) {
return (
<ContextMenuPrimitive.Trigger
data-slot="context-menu-trigger"
className={cn("select-none", className)}
{...props}
/>
)
}
function ContextMenuGroup({
...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Group>) {
return (
<ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} />
)
}
function ContextMenuPortal({
...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Portal>) {
return (
<ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} />
)
}
function ContextMenuSub({
...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Sub>) {
return <ContextMenuPrimitive.Sub data-slot="context-menu-sub" {...props} />
}
function ContextMenuRadioGroup({
...props
}: React.ComponentProps<typeof ContextMenuPrimitive.RadioGroup>) {
return (
<ContextMenuPrimitive.RadioGroup
data-slot="context-menu-radio-group"
{...props}
/>
)
}
function ContextMenuContent({
className,
...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Content> & {
side?: "top" | "right" | "bottom" | "left"
}) {
return (
<ContextMenuPrimitive.Portal>
<ContextMenuPrimitive.Content
data-slot="context-menu-content"
className={cn("z-50 max-h-(--radix-context-menu-content-available-height) min-w-36 origin-(--radix-context-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded border-2 bg-popover p-1 text-popover-foreground shadow-md duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className )}
{...props}
/>
</ContextMenuPrimitive.Portal>
)
}
function ContextMenuItem({
className,
inset,
variant = "default",
...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Item> & {
inset?: boolean
variant?: "default" | "destructive"
}) {
return (
<ContextMenuPrimitive.Item
data-slot="context-menu-item"
data-inset={inset}
data-variant={variant}
className={cn(
"group/context-menu-item relative flex cursor-default items-center gap-1.5 rounded-sm px-2 py-1.5 text-sm outline-none select-none focus:bg-accent focus:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 focus:*:[svg]:text-accent-foreground data-[variant=destructive]:*:[svg]:text-destructive",
className
)}
{...props}
/>
)
}
function ContextMenuSubTrigger({
className,
inset,
children,
...props
}: React.ComponentProps<typeof ContextMenuPrimitive.SubTrigger> & {
inset?: boolean
}) {
return (
<ContextMenuPrimitive.SubTrigger
data-slot="context-menu-sub-trigger"
data-inset={inset}
className={cn(
"flex cursor-default items-center gap-1.5 rounded-sm px-2 py-1.5 text-sm outline-none select-none focus:bg-accent focus:text-accent-foreground data-inset:pl-7 data-open:bg-accent data-open:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
{...props}
>
{children}
<ChevronRightIcon className="cn-rtl-flip ml-auto" />
</ContextMenuPrimitive.SubTrigger>
)
}
function ContextMenuSubContent({
className,
...props
}: React.ComponentProps<typeof ContextMenuPrimitive.SubContent>) {
return (
<ContextMenuPrimitive.SubContent
data-slot="context-menu-sub-content"
className={cn("z-50 min-w-32 origin-(--radix-context-menu-content-transform-origin) overflow-hidden rounded border-2 bg-popover p-1 text-popover-foreground shadow-md duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className )}
{...props}
/>
)
}
function ContextMenuCheckboxItem({
className,
children,
checked,
inset,
...props
}: React.ComponentProps<typeof ContextMenuPrimitive.CheckboxItem> & {
inset?: boolean
}) {
return (
<ContextMenuPrimitive.CheckboxItem
data-slot="context-menu-checkbox-item"
data-inset={inset}
className={cn(
"relative flex cursor-default items-center gap-1.5 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-none select-none focus:bg-accent focus:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
checked={checked}
{...props}
>
<span className="pointer-events-none absolute right-2">
<ContextMenuPrimitive.ItemIndicator>
<CheckIcon />
</ContextMenuPrimitive.ItemIndicator>
</span>
{children}
</ContextMenuPrimitive.CheckboxItem>
)
}
function ContextMenuRadioItem({
className,
children,
inset,
...props
}: React.ComponentProps<typeof ContextMenuPrimitive.RadioItem> & {
inset?: boolean
}) {
return (
<ContextMenuPrimitive.RadioItem
data-slot="context-menu-radio-item"
data-inset={inset}
className={cn(
"relative flex cursor-default items-center gap-1.5 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-none select-none focus:bg-accent focus:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
{...props}
>
<span className="pointer-events-none absolute right-2">
<ContextMenuPrimitive.ItemIndicator>
<CheckIcon />
</ContextMenuPrimitive.ItemIndicator>
</span>
{children}
</ContextMenuPrimitive.RadioItem>
)
}
function ContextMenuLabel({
className,
inset,
...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Label> & {
inset?: boolean
}) {
return (
<ContextMenuPrimitive.Label
data-slot="context-menu-label"
data-inset={inset}
className={cn(
"px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7",
className
)}
{...props}
/>
)
}
function ContextMenuSeparator({
className,
...props
}: React.ComponentProps<typeof ContextMenuPrimitive.Separator>) {
return (
<ContextMenuPrimitive.Separator
data-slot="context-menu-separator"
className={cn("-mx-1 my-1 h-px bg-border", className)}
{...props}
/>
)
}
function ContextMenuShortcut({
className,
...props
}: React.ComponentProps<"span">) {
return (
<span
data-slot="context-menu-shortcut"
className={cn(
"ml-auto text-xs tracking-widest text-muted-foreground group-focus/context-menu-item:text-accent-foreground",
className
)}
{...props}
/>
)
}
export {
ContextMenu,
ContextMenuTrigger,
ContextMenuContent,
ContextMenuItem,
ContextMenuCheckboxItem,
ContextMenuRadioItem,
ContextMenuLabel,
ContextMenuSeparator,
ContextMenuShortcut,
ContextMenuGroup,
ContextMenuPortal,
ContextMenuSub,
ContextMenuSubContent,
ContextMenuSubTrigger,
ContextMenuRadioGroup,
}
अपने प्रोजेक्ट सेटअप के अनुसार इंपोर्ट पाथ अपडेट करें.
उपयोग#
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuTrigger,
} from "@/components/ui/context-menu"<ContextMenu>
<ContextMenuTrigger>Right click here</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem>Profile</ContextMenuItem>
<ContextMenuItem>Billing</ContextMenuItem>
<ContextMenuItem>Team</ContextMenuItem>
<ContextMenuItem>Subscription</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>कंपोज़िशन#
ContextMenu बनाने के लिए निम्नलिखित कंपोज़िशन का उपयोग करें:
ContextMenu
├── ContextMenuTrigger
└── ContextMenuContent
├── ContextMenuGroup
│ ├── ContextMenuLabel
│ ├── ContextMenuItem
│ └── ContextMenuItem
├── ContextMenuSeparator
├── ContextMenuGroup
│ ├── ContextMenuLabel
│ ├── ContextMenuCheckboxItem
│ └── ContextMenuCheckboxItem
├── ContextMenuSeparator
├── ContextMenuGroup
│ ├── ContextMenuLabel
│ └── ContextMenuRadioGroup
│ ├── ContextMenuRadioItem
│ └── ContextMenuRadioItem
└── ContextMenuSub
├── ContextMenuSubTrigger
└── ContextMenuSubContent
└── ContextMenuGroup
├── ContextMenuItem
└── ContextMenuItemउदाहरण#
बुनियादी#
कुछ क्रियाओं वाला एक सरल कॉन्टेक्स्ट मेन्यू.
import {
ContextMenu,
ContextMenuContent,सबमेन्यू#
द्वितीयक क्रियाओं को नेस्ट करने के लिए ContextMenuSub का उपयोग करें.
import {
ContextMenu,
ContextMenuContent,शॉर्टकट#
कीबोर्ड संकेत दिखाने के लिए ContextMenuShortcut जोड़ें.
import {
ContextMenu,
ContextMenuContent,समूह#
संबंधित क्रियाओं को समूहित करें और उन्हें डिवाइडर से अलग करें.
import {
ContextMenu,
ContextMenuContent,आइकन#
त्वरित स्कैनिंग के लिए आइकन को लेबल के साथ मिलाएं.
import {
ClipboardPasteIcon,
CopyIcon,चेकबॉक्स#
टॉगल के लिए ContextMenuCheckboxItem का उपयोग करें.
import {
ContextMenu,
ContextMenuCheckboxItem,रेडियो#
अनन्य विकल्पों के लिए ContextMenuRadioItem का उपयोग करें.
"use client"
import * as React from "react"विनाशकारी#
मेन्यू आइटम को विनाशकारी शैली देने के लिए variant="destructive" का उपयोग करें.
import { ArchiveIcon, PencilIcon, ShareIcon, TrashIcon } from "lucide-react"
import {साइड्स#
side और align प्रॉप्स से सबमेन्यू की प्लेसमेंट नियंत्रित करें.
import {
ContextMenu,
ContextMenuContent,RTL#
Neobrutalism में RTL सपोर्ट सक्षम करने के लिए, RTL कॉन्फ़िगरेशन गाइड देखें.
"use client"
import * as React from "react"मेन्यू को ट्रिगर के लॉजिकल दाईं ओर रखने के लिए side="inline-end" का उपयोग करें.
<ContextMenu>
<ContextMenuTrigger>Right click here</ContextMenuTrigger>
<ContextMenuContent side="inline-end">
<ContextMenuItem>Profile</ContextMenuItem>
<ContextMenuItem>Billing</ContextMenuItem>
<ContextMenuItem>Team</ContextMenuItem>
<ContextMenuItem>Subscription</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>एक्सेसिबिलिटी#
कॉन्टेक्स्ट मेनू WAI-ARIA Menu पैटर्न का पालन करता है: पॉपअप role="menu" रेंडर करता है, चिल्ड्रन menuitem, menuitemcheckbox और menuitemradio होते हैं, खुलने पर फ़ोकस मेनू में जाता है और बंद होने पर ट्रिगर क्षेत्र पर लौटता है। यह ब्राउज़र के contextmenu इवेंट से खुलता है, इसलिए जब ट्रिगर क्षेत्र फ़ोकस-योग्य हो तो Shift + F10 (या समर्पित मेनू कुंजी) काम करती है — अगर चाइल्ड नेटिव रूप से फ़ोकस-योग्य न हो तो tabIndex={0} जोड़ें।
कीबोर्ड इंटरैक्शन:
| कुंजी | क्रिया |
|---|---|
Shift + F10 / menu key | ट्रिगर क्षेत्र पर फ़ोकस होने पर मेनू खोलें |
ArrowDown / ArrowUp | फ़ोकस अगले / पिछले आइटम पर ले जाएँ |
ArrowRight / ArrowLeft | सबमेनू खोलें / बंद करें (RTL में उल्टा) |
Enter / Space | फ़ोकस किए गए आइटम को सक्रिय करें |
Esc | मेनू बंद करें |
| कोई वर्ण टाइप करें | अगले मिलते आइटम पर फ़ोकस ले जाएँ (typeahead) |
API रेफ़रेंस#
अधिक जानकारी के लिए Base UI डॉक्युमेंटेशन देखें.