elements
lifecycle
browser
- useAudio
- useBattery
- useBluetooth
- useBreakpoints
- useBroadcastChannel
- useBrowserLocation
- useClipboard
- useCopy
- useCssVar
- useDisplayMedia
- useDocumentEvent
- useDocumentTitle
- useDocumentVisibility
- useEventListener
- useEventSource
- useEyeDropper
- useFavicon
- useFileSystemAccess
- useFps
- useFullscreen
- useGamepad
- useGeolocation
- useMeasure
- useMediaControls
- useMediaQuery
- useMemory
- useNetwork
- useObjectUrl
- useOnline
- useOtpCredential
- usePermission
- usePictureInPicture
- usePointerLock
- usePostMessage
- useRaf
- useShare
- useSpeechRecognition
- useSpeechSynthesis
- useSticky
utilities
state
user
sensors
TK
reacuseTokyo, Japan

284,910 likes
reacuse Neon nights in Shibuya 🌃 Currently 18°C and clear.
9.7M residents · View all 1,204 commentsimport { useClickOutside, useContextMenu } from '@siberiacancode/reactuse';
import {
BookmarkIcon,
HeartIcon,
MapPinIcon,
MessageCircleIcon,
SendIcon,
Share2Icon,
Trash2Icon
} from 'lucide-react';
const Demo = () => {
const contextMenu = useContextMenu<HTMLDivElement>();
const menuRef = useClickOutside<HTMLDivElement>(() => contextMenu.close());
return (
<section className='flex flex-col items-center p-4'>
<div
ref={contextMenu.ref}
className='bg-card w-full max-w-sm cursor-context-menu overflow-hidden rounded-2xl select-none'
>
<div className='flex items-center gap-3 px-4 py-3'>
<div data-size='lg' data-slot='avatar'>
<span data-slot='avatar-fallback'>TK</span>
</div>
<div className='flex flex-1 flex-col leading-tight'>
<span className='text-foreground text-sm font-semibold'>reacuse</span>
<span className='text-muted-foreground flex items-center gap-1 text-xs'>
<MapPinIcon className='size-3' />
Tokyo, Japan
</span>
</div>
</div>
<div className='relative aspect-square'>
<img alt='Tokyo' className='size-full object-cover' src='/new/images/tokyo.png' />
</div>
<div className='flex items-center gap-4 px-4 pt-3'>
<HeartIcon className='size-6' />
<MessageCircleIcon className='size-6' />
<SendIcon className='size-6' />
<BookmarkIcon className='ml-auto size-6' />
</div>
<div className='flex flex-col gap-1 px-4 py-2'>
<span className='text-foreground text-sm font-semibold'>284,910 likes</span>
<p className='text-foreground text-sm'>
<span className='font-semibold'>reacuse</span> Neon nights in Shibuya 🌃 Currently 18°C
and clear.
</p>
<span className='text-muted-foreground text-xs'>
9.7M residents · View all 1,204 comments
</span>
</div>
</div>
{contextMenu.opened && contextMenu.position && (
<div
ref={menuRef}
className='fixed z-50 w-48'
data-slot='dropdown-menu-content'
style={{ top: contextMenu.position.y, left: contextMenu.position.x }}
>
<div data-slot='dropdown-menu-item'>
<HeartIcon />
Like post
</div>
<div data-slot='dropdown-menu-item'>
<BookmarkIcon />
Save
</div>
<div data-slot='dropdown-menu-item'>
<Share2Icon />
Share
<span data-slot='dropdown-menu-shortcut'>⌘S</span>
</div>
<div data-slot='dropdown-menu-separator' />
<div data-slot='dropdown-menu-item' data-variant='destructive'>
<Trash2Icon />
Remove
</div>
</div>
)}
</section>
);
};
export default Demo;
Installation
pnpm add @siberiacancode/reactuseUsage
const menu = useContextMenu(ref, (position) => console.log(position));
// or
const menu = useContextMenu(ref, options);
// or
const { ref, opened, position } = useContextMenu((position) => console.log(position));
// or
const { ref, opened, position } = useContextMenu(options);Type Declarations
import type { HookTarget } from '@/utils/helpers';
import type { StateRef } from '../useRefState/useRefState';
export type ContextMenuEvent = MouseEvent | TouchEvent;
export interface ContextMenuPosition {
/** The x coordinate of the event */
x: number;
/** The y coordinate of the event */
y: number;
}
export type UseContextMenuCallback = (
position: ContextMenuPosition,
event: ContextMenuEvent
) => void;
export interface UseContextMenuOptions {
/** The long press delay on touch devices in milliseconds */
delay?: number;
/** The enabled state of the hook */
enabled?: boolean;
/** The callback function to be invoked when the menu opens */
onOpen?: UseContextMenuCallback;
/** The callback function to be invoked when the menu closes */
onClose?: () => void;
/** The callback function to be invoked when the interaction ends */
onEnd?: (event: ContextMenuEvent) => void;
/** The callback function to be invoked when the interaction starts */
onStart?: (event: ContextMenuEvent) => void;
}
export interface UseContextMenuReturn {
/** The context menu opened state */
opened: boolean;
/** The context menu position */
position?: ContextMenuPosition;
/** Close the context menu */
close: () => void;
/** Open the context menu */
open: (position: ContextMenuPosition, event?: ContextMenuEvent) => void;
}
export interface UseContextMenu {
(target: HookTarget, callback?: UseContextMenuCallback): UseContextMenuReturn;
(target: HookTarget, options?: UseContextMenuOptions): UseContextMenuReturn;
<Target extends Element>(
callback?: UseContextMenuCallback,
target?: never
): UseContextMenuReturn & { ref: StateRef<Target> };
<Target extends Element>(
options?: UseContextMenuOptions,
target?: never
): UseContextMenuReturn & { ref: StateRef<Target> };
}API
Parameters
| Name | Type | Default | Note |
|---|---|---|---|
| target | HookTarget | - | The target element for context menu handling |
| callback | UseContextMenuCallback | - | The callback function to be invoked when the menu opens |
Returns
UseContextMenuReturnParameters
| Name | Type | Default | Note |
|---|---|---|---|
| target | HookTarget | - | The target element for context menu handling |
| options.delay | number | 500 | The long press delay on touch devices in milliseconds |
| options.enabled | boolean | true | The enabled state of the hook |
| options.onOpen | UseContextMenuCallback | - | The callback function to be invoked when the menu opens |
| options.onClose | () => void | - | The callback function to be invoked when the menu closes |
| options.onStart | (event: ContextMenuEvent) => void | - | The callback function to be invoked when the interaction starts |
| options.onEnd | (event: ContextMenuEvent) => void | - | The callback function to be invoked when the interaction ends |
Returns
UseContextMenuReturnParameters
| Name | Type | Default | Note |
|---|---|---|---|
| callback | UseContextMenuCallback | - | The callback function to be invoked when the menu opens |
Returns
UseContextMenuReturn & { ref: StateRef<Target> }Parameters
| Name | Type | Default | Note |
|---|---|---|---|
| options.delay | number | 500 | The long press delay on touch devices in milliseconds |
| options.enabled | boolean | true | The enabled state of the hook |
| options.onOpen | UseContextMenuCallback | - | The callback function to be invoked when the menu opens |
| options.onClose | () => void | - | The callback function to be invoked when the menu closes |
| options.onStart | (event: ContextMenuEvent) => void | - | The callback function to be invoked when the interaction starts |
| options.onEnd | (event: ContextMenuEvent) => void | - | The callback function to be invoked when the interaction ends |
Returns
UseContextMenuReturn & { ref: StateRef<Target> }Contributors
ddebabin
Last updated on