Primitives
Trigger Menu
Caret-anchored command or mention menu for text editors.
Composition
The preferred shape for composing the installed primitive from its exported parts.
Parts
Exported compound parts from the installed source.
TriggerMenu├── TriggerMenuList├── TriggerMenuItem├── TriggerMenuIcon├── TriggerMenuEmpty├── TriggerMenuGroup└── TriggerMenuGroupLabelThe refined source installs this primitive from src/registry/sources/refined/ui/trigger-menu.tsx. Install it on its own with the command above, or inspect the source below.
npx shadcn@latest add http://127.0.0.1:3000/r/refined/trigger-menu.jsonInstalled dependencies
Installed with this primitive because the slot depends on them; they are support files, not standalone sidebar items.
Trigger menu engine
src/registry/hooks/use-trigger-menu.tsSupportTextarea binding
src/registry/hooks/use-textarea-trigger-menu.tsSupportTrigger detection
src/registry/lib/trigger-detect.tsSupportSurface variants
src/registry/sources/refined/surface-variants.tsSupportRaw code
Primary installed primitive source
Trigger menu slot
src/registry/sources/refined/ui/trigger-menu.tsx
"use client";import { Popover as PopoverPrimitive } from "@base-ui/react/popover";import type { TriggerMenuEmptyProps, TriggerMenuGroupLabelProps, TriggerMenuGroupProps, TriggerMenuIconProps, TriggerMenuItemProps, TriggerMenuListProps, TriggerMenuProps,} from "@/components/refined-ui/contracts";import { cn } from "@/components/refined-ui/lib/cn";import { skinEffects, skinId, skinSlot } from "@/components/refined-ui/skin";import { floatingListContentClasses, floatingListItemClasses } from "@/components/refined-ui/surface-variants";// VIEW half of trigger-menu primitive: Base UI Popover controlled by headless engine (open + virtual anchor at caret rect), not a trigger button.// Rides shared popover token set (--radius-popover, shadow-pop); rows match menu/select rows (--control-h-xs, --radius-popup-item).// initialFocus/finalFocus={false} keep focus in editor so arrow/Enter keep flowing to caret while menu is up.export function TriggerMenu({ open, onOpenChange, anchorRect, side = "top", align = "start", sideOffset = 8, className, children,}: TriggerMenuProps) { return ( <PopoverPrimitive.Root open={open} onOpenChange={(next, eventDetails) => onOpenChange?.(next, eventDetails)} modal={false}> <PopoverPrimitive.Portal> {/* Portals land outside token-scoped subtree (and ChatScene's overflow clip); positioner re-asserts skin scope itself. Anchor = virtual element at caret rect engine reported. */} <PopoverPrimitive.Positioner data-skin={skinId()} data-effects={skinEffects()} anchor={anchorRect === null ? undefined : () => ({ getBoundingClientRect: () => anchorRect })} side={side} align={align} sideOffset={sideOffset} className="z-[80] outline-none" > <PopoverPrimitive.Popup data-ui="agent" data-slot="trigger-menu" initialFocus={false} finalFocus={false} className={cn( "max-h-[min(18rem,var(--available-height))] w-64 max-w-[var(--available-width)] overflow-y-auto", floatingListContentClasses, skinSlot("trigger-menu", {}), className, )} > {children} </PopoverPrimitive.Popup> </PopoverPrimitive.Positioner> </PopoverPrimitive.Portal> </PopoverPrimitive.Root> );}export function TriggerMenuList({ className, ...props }: TriggerMenuListProps) { return ( <div data-ui="agent" data-slot="trigger-menu-list" role="listbox" className={cn("flex flex-col gap-0.5", skinSlot("trigger-menu-list", {}), className)} {...props} /> );}export function TriggerMenuItem({ className, active = false, disabled = false, onMouseDown, ...props }: TriggerMenuItemProps) { return ( <div data-ui="agent" data-slot="trigger-menu-item" role="option" // Listbox options driven by editor's keyboard, not tab focus; -1 keeps them out of tab order while satisfying focusable-interactive contract. tabIndex={-1} aria-selected={active} aria-disabled={disabled || undefined} data-highlighted={active ? "" : undefined} data-disabled={disabled ? "" : undefined} // Keep focus in the editor/textarea when a row is clicked so the insertion still targets the caret. onMouseDown={(event) => { event.preventDefault(); onMouseDown?.(event); }} className={cn(floatingListItemClasses, skinSlot("trigger-menu-item", { highlighted: active, disabled }), className)} {...props} /> );}export function TriggerMenuIcon({ className, ...props }: TriggerMenuIconProps) { return ( <span data-ui="agent" data-slot="trigger-menu-icon" className={cn( "flex size-5 shrink-0 items-center justify-center text-muted-foreground [&_svg]:size-4", skinSlot("trigger-menu-icon", {}), className, )} {...props} /> );}export function TriggerMenuEmpty({ className, ...props }: TriggerMenuEmptyProps) { return ( <div data-ui="agent" data-slot="trigger-menu-empty" className={cn("px-[calc(var(--padding-x)*0.5)] py-2 text-body text-muted-foreground", skinSlot("trigger-menu-empty", {}), className)} {...props} /> );}export function TriggerMenuGroup({ className, ...props }: TriggerMenuGroupProps) { return ( <div data-ui="agent" data-slot="trigger-menu-group" className={cn("flex flex-col gap-0.5", skinSlot("trigger-menu-group", {}), className)} {...props} /> );}export function TriggerMenuGroupLabel({ className, ...props }: TriggerMenuGroupLabelProps) { return ( <div data-ui="agent" data-slot="trigger-menu-group-label" className={cn( "px-[calc(var(--padding-x)*0.5)] pb-0.5 pt-1 text-micro font-medium uppercase tracking-[0.08em] text-muted-foreground", skinSlot("trigger-menu-group-label", {}), className, )} {...props} /> );}