A comprehensive collection of 75+ React hooks for state and UI management including storage, events, browser APIs, and performance optimizations
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Event handling hooks for click detection, keyboard shortcuts, mouse interactions, hover states, focus management, and touch gestures.
Detect clicks outside target element(s) with configurable events and multiple node support.
/**
* Detect clicks outside target element(s)
* @param handler - Function to call when click outside occurs
* @param events - Array of event names to listen for (default: ['mousedown', 'touchstart'])
* @param nodes - Additional nodes to consider as "inside"
* @returns Ref callback to attach to target element
*/
function useClickOutside<T extends HTMLElement = any>(
handler: () => void,
events?: string[] | null,
nodes?: HTMLElement[]
): React.RefCallback<T | null>;Usage Examples:
import { useClickOutside } from "@mantine/hooks";
import { useRef } from "react";
// Basic modal/dropdown
function Modal({ onClose }: { onClose: () => void }) {
const ref = useClickOutside(onClose);
return <div ref={ref}>Modal content</div>;
}
// Multiple elements considered "inside"
function ComplexDropdown() {
const triggerRef = useRef<HTMLButtonElement>(null);
const dropdownRef = useClickOutside(
() => setOpened(false),
['mousedown', 'touchstart'],
[triggerRef.current] // Don't close when clicking trigger
);
return (
<>
<button ref={triggerRef}>Open</button>
<div ref={dropdownRef}>Dropdown content</div>
</>
);
}Keyboard shortcuts handler with key combinations and configurable options.
/**
* Keyboard shortcuts handler
* @param hotkeys - Array of [key combination, handler, options] tuples
* @param tagsToIgnore - HTML tags to ignore (default: ['INPUT', 'TEXTAREA', 'SELECT'])
* @param triggerOnContentEditable - Whether to trigger on contentEditable elements
*/
function useHotkeys(
hotkeys: HotkeyItem[],
tagsToIgnore?: string[],
triggerOnContentEditable?: boolean
): void;
/**
* Get hotkey handler for manual event handling
* @param hotkeys - Array of hotkey configurations
* @returns Event handler function
*/
function getHotkeyHandler(hotkeys: HotkeyItem[]): (event: React.KeyboardEvent<HTMLElement> | KeyboardEvent) => void;
type HotkeyItem = [string, (event: KeyboardEvent) => void, HotkeyItemOptions?];
interface HotkeyItemOptions {
preventDefault?: boolean;
usePhysicalKeys?: boolean;
}Usage Examples:
import { useHotkeys, getHotkeyHandler } from "@mantine/hooks";
// Global hotkeys
function App() {
useHotkeys([
['mod+S', () => save()], // Cmd+S on Mac, Ctrl+S on Windows
['mod+K', () => openSearch(), { preventDefault: true }],
['Escape', () => closeModal()],
['shift+?', () => showHelp()],
]);
}
// Manual event handling
function Editor() {
const handleKeyDown = getHotkeyHandler([
['mod+B', () => toggleBold()],
['mod+I', () => toggleItalic()],
]);
return <textarea onKeyDown={handleKeyDown} />;
}Detect hover state on elements with ref-based attachment.
/**
* Detect hover state on elements
* @returns Object with hover state and ref callback
*/
function useHover<T extends HTMLElement = any>(): UseHoverReturnValue<T>;
interface UseHoverReturnValue<T extends HTMLElement = any> {
hovered: boolean;
ref: React.RefCallback<T | null>;
}Usage Examples:
import { useHover } from "@mantine/hooks";
function HoverCard() {
const { hovered, ref } = useHover();
return (
<div ref={ref} style={{ background: hovered ? 'blue' : 'gray' }}>
{hovered ? 'Hovered!' : 'Hover me'}
</div>
);
}Mouse/touch drag interactions with position tracking and directional support.
/**
* Mouse/touch drag interactions with position tracking
* @param onChange - Callback fired when position changes
* @param handlers - Optional start/end handlers
* @param dir - Text direction for RTL support
* @returns Object with ref callback and active state
*/
function useMove<T extends HTMLElement = any>(
onChange: (value: UseMovePosition) => void,
handlers?: UseMoveHandlers,
dir?: 'ltr' | 'rtl'
): UseMoveReturnValue<T>;
/**
* Clamp position values to 0-1 range
* @param position - Position object to clamp
* @returns Clamped position
*/
function clampUseMovePosition(position: UseMovePosition): UseMovePosition;
interface UseMovePosition {
x: number; // 0-1 range
y: number; // 0-1 range
}
interface UseMoveHandlers {
onScrubStart?: () => void;
onScrubEnd?: () => void;
}
interface UseMoveReturnValue<T extends HTMLElement = any> {
ref: React.RefCallback<T | null>;
active: boolean;
}Usage Examples:
import { useMove, clampUseMovePosition } from "@mantine/hooks";
// Color picker
function ColorPicker() {
const [value, setValue] = useState({ x: 0.5, y: 0.5 });
const { ref, active } = useMove((position) => {
setValue(clampUseMovePosition(position));
}, {
onScrubStart: () => console.log('Started dragging'),
onScrubEnd: () => console.log('Stopped dragging')
});
return (
<div ref={ref} style={{ position: 'relative', width: 200, height: 200 }}>
<div
style={{
position: 'absolute',
left: `${value.x * 100}%`,
top: `${value.y * 100}%`,
transform: 'translate(-50%, -50%)'
}}
>
Thumb
</div>
</div>
);
}Detect focus within element tree with callbacks for focus/blur events.
/**
* Detect focus within element tree
* @param options - Configuration for focus callbacks
* @returns Object with focus state and ref callback
*/
function useFocusWithin<T extends HTMLElement = any>(options?: UseFocusWithinOptions): UseFocusWithinReturnValue<T>;
interface UseFocusWithinOptions {
onFocus?: () => void;
onBlur?: () => void;
}
interface UseFocusWithinReturnValue<T extends HTMLElement = any> {
focused: boolean;
ref: React.RefCallback<T | null>;
}Trap focus within element for accessibility (modals, dropdowns).
/**
* Trap focus within element for accessibility
* @param active - Whether focus trap is active
* @returns Ref callback to attach to container element
*/
function useFocusTrap(active?: boolean): React.RefCallback<HTMLElement | null>;Detect long press gestures with configurable threshold and callbacks.
/**
* Detect long press gestures
* @param callback - Function to call on long press
* @param options - Configuration for threshold and callbacks
* @returns Object with ref callback
*/
function useLongPress<T extends HTMLElement = any>(
callback: () => void,
options?: UseLongPressOptions
): UseLongPressReturnValue<T>;
interface UseLongPressOptions {
threshold?: number; // Duration in ms (default: 500)
onStart?: () => void;
onFinish?: () => void;
onCancel?: () => void;
}
interface UseLongPressReturnValue<T extends HTMLElement = any> {
ref: React.RefCallback<T | null>;
}Attach event listeners to elements with ref callback and automatic cleanup.
/**
* Attach event listeners to elements
* @param type - Event type
* @param listener - Event handler function
* @param options - Event listener options
* @returns Ref callback to attach to target element
*/
function useEventListener<K extends keyof HTMLElementEventMap, T extends HTMLElement = any>(
type: K,
listener: (this: HTMLDivElement, ev: HTMLElementEventMap[K]) => any,
options?: boolean | AddEventListenerOptions
): React.RefCallback<T | null>;Attach event listeners to window object with automatic cleanup.
/**
* Attach event listeners to window object
* @param type - Event type
* @param listener - Event handler function
* @param options - Event listener options
*/
function useWindowEvent<K extends string>(
type: K,
listener: K extends keyof WindowEventMap
? (this: Window, ev: WindowEventMap[K]) => void
: (this: Window, ev: CustomEvent) => void,
options?: boolean | AddEventListenerOptions
): void;Usage Examples:
import { useEventListener, useWindowEvent } from "@mantine/hooks";
// Element-specific events
function InteractiveElement() {
const ref = useEventListener('click', (event) => {
console.log('Element clicked', event);
});
return <div ref={ref}>Click me</div>;
}
// Global window events
function WindowEventHandler() {
useWindowEvent('resize', () => {
console.log('Window resized');
});
useWindowEvent('keydown', (event) => {
if (event.key === 'Escape') {
console.log('Escape pressed');
}
});
return <div>Component with window event handlers</div>;
}