Context Menu
shadcn-lit-registry/context-menuFreeComponent
Displays a menu to the user at the cursor position when right-clicking on a trigger area. Supports checkboxes, radio groups, nested submenus, keyboard navigation, and accessibility features.
Install it
npx shadcn@latest add https://lit-registry.lloydrichards.dev/r/context-menu.jsonSource
1import { css, html, LitElement, nothing, type PropertyValues } from "lit";2import {3 customElement,4 property,5 query,6 queryAssignedElements,7 state,8} from "lit/decorators.js";9import { unsafeSVG } from "lit/directives/unsafe-svg.js";10import { Check, ChevronRight, Circle } from "lucide-static";1112import { TW } from "@/registry/lib/tailwindMixin";13import { cn } from "@/registry/lib/utils";14import "@/registry/ui/popover/popover";1516export type ContextMenuProperties = {17 open?: boolean;18 modal?: boolean;19 disabled?: boolean;20};2122type VirtualAnchor = {23 getBoundingClientRect(): DOMRect;24};2526type AnchorElement = Element | VirtualAnchor;2728export type MenuItemWithProperties = HTMLElement & {29 disabled?: boolean;30 highlighted?: boolean;31 value?: string;32 checked?: boolean;33};3435export function isMenuItemElement(36 element: HTMLElement,37): element is MenuItemWithProperties {38 const validTags = [39 "UI-CONTEXT-MENU-ITEM",40 "UI-CONTEXT-MENU-CHECKBOX-ITEM",41 "UI-CONTEXT-MENU-RADIO-ITEM",42 "UI-CONTEXT-MENU-SUB-TRIGGER",43 ];44 return validTags.includes(element.tagName);45}4647const isNode = (value: EventTarget | null): value is Node => {48 return value instanceof Node;49};5051@customElement("ui-context-menu")52export class ContextMenu53 extends TW(LitElement)54 implements ContextMenuProperties55{56 static styles = css`57 :host {58 display: contents;59 }60 `;6162 @property({ type: Boolean, reflect: true }) open = false;63 @property({ type: Boolean }) modal = true;64 @property({ type: Boolean }) disabled = false;6566 @state() private cursorX = 0;67 @state() private cursorY = 0;68 @state() private virtualAnchor?: AnchorElement;6970 @query("ui-popover") popoverElement?: HTMLElement;7172 private clickAwayHandler = (e: MouseEvent) => {73 if (!this.open) return;7475 if (!isNode(e.target)) return;7677 if (this.querySelector("ui-context-menu-content")?.contains(e.target))78 return;79 if (this.querySelector("ui-popover")?.contains(e.target)) return;8081 const triggerSlot = this.shadowRoot?.querySelector<HTMLSlotElement>(82 'slot[name="trigger"]',83 );84 if (triggerSlot) {85 const assignedElements = triggerSlot.assignedElements({ flatten: true });86 for (const el of assignedElements) {87 if (el.contains(e.target)) return;88 }89 }9091 this.open = false;92 };9394 private escapeHandler = (e: KeyboardEvent) => {95 if (e.key === "Escape" && this.open) {96 e.preventDefault();97 this.open = false;98 }99 };100101// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from shadcn-lit-registry
All 26 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | shadcn-lit-registry | Components | Free | 1 dep · 2 files | |
| Avataravatar | shadcn-lit-registry | Components | Free | no deps · 2 files | |
| Badgebadge | shadcn-lit-registry | Components | Free | no deps · 2 files | |
| Buttonbutton | shadcn-lit-registry | Components | Free | 1 dep · 2 files | |
| Cardcard | shadcn-lit-registry | Components | Free | no deps · 2 files | |
| Checkboxcheckbox | shadcn-lit-registry | Components | Free | 1 dep · 2 files | |
| Collapsiblecollapsible | shadcn-lit-registry | Components | Free | 1 dep · 2 files | |
| Commandcommand | shadcn-lit-registry | Components | Free | 1 dep · 2 files |
