BlockDex

Components

Registries

Free blocks

Method

BlockDex

Components

Registries

Free blocks

Method

Open API

BlockDex

Components

Registries

Free blocks

Method

Open API

Components/ns-ui/context-menu-unfold

Context Menu Unfold

ns-ui/context-menu-unfold
FreeComponent

A context menu that unfolds like a pocket knife — items swing out from a hinged spine as slim blades, staggered from folded to open, with a hairline edge highlight while swinging; submenus unfold as a second, smaller knife from a blade's tip.

Live preview

live · rendered by the registry
Rendered by ns-ui on their own page — this is the component running, not a screenshot of it.

Install it

npx shadcn@latest add https://design.helpmarq.com/r/context-menu-unfold.json

Source

registry/core/context-menu-unfold/component.tsxdesign.helpmarq.com/r/context-menu-unfold.json · first 6 KB
1"use client";
2
3import {
4 useCallback,
5 useEffect,
6 useId,
7 useMemo,
8 useRef,
9 useState,
10 type KeyboardEvent as ReactKeyboardEvent,
11 type MouseEvent as ReactMouseEvent,
12 type ReactNode,
13} from "react";
14
15// ---------------------------------------------------------------------------
16// JackKnife — a context menu that unfolds like a pocket knife. A spine
17// anchors at the trigger point (the pointer for a right-click, or the
18// trigger button's own position for the accessible trigger); menu items are
19// slim "blades" hinged at the spine edge, each swinging in with a staggered
20// rotation from folded (~80deg, tucked flat against the spine) to open
21// (0deg). Every swing is a one-shot ref-driven CSS transition (transform +
22// a border-color pulse for the hairline edge highlight) — timed with a
23// per-item delay for the stagger — not a continuous rAF loop. A submenu is
24// the same component recursively, anchored at the parent blade's tip.
25// Distinct from menu-nested-trays (telescoping trays) and dropdown-drape (cloth
26// dropdown): this is a radial-fold context-menu primitive.
27// ---------------------------------------------------------------------------
28
29export interface JackKnifeItem {
30 id: string;
31 label: string;
32 shortcut?: string;
33 disabled?: boolean;
34 submenu?: JackKnifeItem[];
35}
36
37export interface JackKnifeProps {
38 items: JackKnifeItem[];
39 onSelect?: (id: string) => void;
40 /** region that opens the menu on right-click; the trigger button always works too */
41 children?: ReactNode;
42 /** accessible name for the trigger button and the menu itself */
43 label?: string;
44 className?: string;
45}
46
47type Anchor = { x: number; y: number; side: "left" | "right" };
48
49const OPEN_MS = 260;
50const OPEN_STAGGER_MS = 38;
51const CLOSE_MS = 150;
52const CLOSE_STAGGER_MS = 22;
53const HAIRLINE_HOLD_MS = 120;
54const TYPEAHEAD_RESET_MS = 700;
55const ITEM_W = 200;
56const EDGE_MARGIN = 10;
57
58function computeAnchor(x: number, y: number): Anchor {
59 const side: Anchor["side"] = x + ITEM_W + EDGE_MARGIN > window.innerWidth ? "left" : "right";
60 return { x, y, side };
61}
62
63function clampTop(y: number, height: number) {
64 return Math.min(Math.max(EDGE_MARGIN, y), Math.max(EDGE_MARGIN, window.innerHeight - height - EDGE_MARGIN));
65}
66
67function foldItem(
68 el: HTMLElement | null,
69 index: number,
70 opening: boolean,
71 side: "left" | "right",
72 reduced: boolean
73) {
74 if (!el) return;
75 const sign = side === "right" ? -1 : 1;
76 if (reduced) {
77 el.style.transition = "none";
78// … truncated

Files it writes

  • registry/core/context-menu-unfold/component.tsx

Facts

Registry
ns-ui
Type
registry:ui
Access
Free
Files written
1
Licence
MIT
First indexed
2026-08-02
Last confirmed
yesterday

Go to the source

Docs on ns-ui design.helpmarq.com nikolas-sapa/ns-ui on GitHub Raw registry item This item as JSON

More from ns-ui

All 228 items
Same registry, same kind — the ones you would have found next
ComponentRegistryKindAccessInstallsCommand
Accordion Latchaccordion-latchns-uiComponentsFreeno deps
Approval Inline Diffapproval-inline-diffns-uiComponentsFreeno deps
ASCII Engraving Contourascii-engraving-contourns-uiComponentsFreeno deps
ASCII Globe Spinascii-globe-spinns-uiComponentsFreeno deps
ASCII Torus Donutascii-torus-donutns-uiComponentsFreeno deps
Autosave Ratchetautosave-ratchetns-uiComponentsFreeno deps
Avatar Stack Flockavatar-stack-flockns-uiComponentsFreeno deps
Background ASCII Ditherbackground-ascii-ditherns-uiComponentsFreeno deps
BlockDex

Built by

Kynth Studio

Index

Components
Registries
Method
Open API

Guides

shadcn component libraries
Best shadcn registries
Free shadcn blocks

Reference

Corpus counts
Crawl health
hello@kynth.studio
Privacy
Terms

BlockDex

BlockDex

Built by

Kynth Studio

Index

Components
Registries
Method
Open API

Guides

shadcn component libraries
Best shadcn registries
Free shadcn blocks

Reference

Corpus counts
Crawl health
hello@kynth.studio
Privacy
Terms

BlockDex

BlockDex

Built by

Kynth Studio

Index

Components
Registries
Method
Open API

Guides

shadcn component libraries
Best shadcn registries
Free shadcn blocks

Reference

Corpus counts
Crawl health
hello@kynth.studio
Privacy
Terms

BlockDex