From 0073fa37364cbff6a14dd7214f6da668770de3af Mon Sep 17 00:00:00 2001 From: Abhishek Chaurasiya Date: Sun, 26 Oct 2025 20:42:57 +0530 Subject: [PATCH] Add useKeyPress hook for keyboard event handling --- index.d.ts | 10 ++++++++++ index.js | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/index.d.ts b/index.d.ts index db01dc2..01c53c8 100644 --- a/index.d.ts +++ b/index.d.ts @@ -231,6 +231,16 @@ declare module "@uidotdev/usehooks" { } ): "unknown" | "loading" | "ready" | "error"; + export function useKeyPress( + key: string, + cb: (e: KeyboardEvent) => void, + options?: { + event?: string; + target?: EventTarget | Window | { current: EventTarget | null } | null; + eventOptions?: AddEventListenerOptions; + } + ): void; + export function useSessionStorage( key: string, initialValue: T diff --git a/index.js b/index.js index f6e4fe2..e00dc38 100644 --- a/index.js +++ b/index.js @@ -1365,3 +1365,46 @@ export function useWindowSize() { return size; } + +export function useKeyPress(key, cb, options = {}) { + const { event = "keydown", target = typeof window !== "undefined" ? window : null, eventOptions } = options; + + const cbRef = React.useRef(cb); + + React.useLayoutEffect(() => { + cbRef.current = cb; + }, [cb]); + + React.useEffect(() => { + if (!target) return; + + const getTarget = () => { + // support passing a DOM node, window, or a ref-like object + if (typeof target === "object" && "current" in target) { + return target.current; + } + + return target; + }; + + const t = getTarget(); + if (!t || !t.addEventListener) return; + + const handler = (e) => { + // KeyboardEvent key match + try { + if (e.key === key) { + cbRef.current && cbRef.current(e); + } + } catch (err) { + // ignore + } + }; + + t.addEventListener(event, handler, eventOptions); + + return () => { + t.removeEventListener(event, handler, eventOptions); + }; + }, [key, event, target, eventOptions]); +}