useKeyPress
A React hook that detects when a specific key is pressed.
Installation
npx shadcn@latest add https://r.fiberui.com/r/hooks/use-key-press.jsonFeatures
- Specific Key Detection - Detects press state of any key by name.
- Real-time Updates - Updates state on
keydownandkeyup. - Global Listener - Listens to window events, so it works anywhere on the page.
Source Code
View the full hook implementation in the Hook Source Code section below.
Interactive Example
Key Press Detection
Press the following keys to see their state:
EnterReleased
EscapeReleased
SpaceReleased
ShiftReleased
"use client";
import { useKeyPress } from "@repo/hooks/dom/use-key-press";
import { Keyboard } from "lucide-react";
export const Example1 = () => {
// Track specific keys
const isEnterPressed = useKeyPress("Enter");
const isEscapePressed = useKeyPress("Escape");
const isSpacePressed = useKeyPress(" ");
const isShiftPressed = useKeyPress("Shift");
return (
<div className="flex w-full max-w-md flex-col gap-4">
<div className="flex items-center gap-2">
<Keyboard className="text-primary h-5 w-5" />
<h3 className="font-semibold">Key Press Detection</h3>
</div>
<p className="text-muted-foreground text-sm">
Press the following keys to see their state:
</p>
<div className="grid grid-cols-2 gap-3">
<KeyDisplay label="Enter" isPressed={isEnterPressed} />
<KeyDisplay label="Escape" isPressed={isEscapePressed} />
<KeyDisplay label="Space" isPressed={isSpacePressed} />
<KeyDisplay label="Shift" isPressed={isShiftPressed} />
</div>
</div>
);
};
const KeyDisplay = ({
label,
isPressed,
}: {
label: string;
isPressed: boolean;
}) => (
<div
className={`flex items-center justify-between rounded-lg border px-3 py-2 text-sm transition-all duration-150 ${
isPressed
? "border-primary bg-primary/10 text-primary scale-105 font-medium shadow-sm"
: "border-muted bg-muted/20 text-muted-foreground"
}`}
>
<span>{label}</span>
<span className="text-xs">{isPressed ? "Pressed" : "Released"}</span>
</div>
);
const isEnterPressed = useKeyPress("Enter");
const isEscapePressed = useKeyPress("Escape");
if (isEnterPressed) {
console.log("Enter key is down!");
}Game Controls
Detects multiple keys for movement (WASD or Arrows).
Game Controls
W / ↑
A / ←
S / ↓
D / →
Character is idle.
"use client";
import { useKeyPress } from "@repo/hooks/dom/use-key-press";
import { Gamepad2 } from "lucide-react";
export const Example2 = () => {
const up = useKeyPress("ArrowUp");
const down = useKeyPress("ArrowDown");
const left = useKeyPress("ArrowLeft");
const right = useKeyPress("ArrowRight");
const w = useKeyPress("w");
const a = useKeyPress("a");
const s = useKeyPress("s");
const d = useKeyPress("d");
const isMoving = up || down || left || right || w || a || s || d;
return (
<div className="flex w-full max-w-md flex-col items-center gap-6">
<div className="flex items-center gap-2">
<Gamepad2
className={`h-5 w-5 ${isMoving ? "text-primary animate-pulse" : ""}`}
/>
<h3 className="font-semibold">Game Controls</h3>
</div>
<div className="grid grid-cols-3 gap-2">
<div />
<KeyCap label="W / ↑" active={up || w} />
<div />
<KeyCap label="A / ←" active={left || a} />
<KeyCap label="S / ↓" active={down || s} />
<KeyCap label="D / →" active={right || d} />
</div>
<p className="text-muted-foreground text-center text-sm">
{isMoving ? "Character is moving!" : "Character is idle."}
</p>
</div>
);
};
const KeyCap = ({ label, active }: { label: string; active: boolean }) => (
<div
className={`flex h-12 w-16 items-center justify-center rounded-lg border-b-4 text-sm font-bold transition-all ${
active
? "border-primary bg-primary text-primary-foreground translate-y-1 border-b-0"
: "border-muted-foreground/30 bg-muted"
}`}
>
{label}
</div>
);
const up = useKeyPress("ArrowUp");
const w = useKeyPress("w");
const isMovingUp = up || w; API Reference
Signature
const isPressed = useKeyPress(targetKey);Parameters
| Parameter | Type | Description |
|---|---|---|
targetKey | string | The key to listen for (e.g., "Enter", "Escape", "a", "Shift"). Matches event.key. |
Returns
| Type | Description |
|---|---|
boolean | true if the key is currently pressed, false otherwise. |
Hook Source Code
import { useState, useCallback, useRef, useEffect } from "react";
import {
useEventListener,
EventListenerOptions,
} from "@repo/hooks/dom/use-event-listener";
/**
* useKeyPress - Detect when a specific key is pressed
*
* @param targetKey - The key to listen for (e.g., "Escape", "Enter", "a")
* @param callback - Optional callback when key is pressed
* @param options - Optional event listener options
* @returns boolean indicating if the key is currently pressed
*
* @example
* // Using the boolean state
* const isEscapePressed = useKeyPress("Escape");
*
* // Using the callback
* useKeyPress("Enter", () => submitForm());
*
* // With options
* useKeyPress("Tab", () => handleTab(), { preventDefault: true });
*/
export function useKeyPress(
targetKey: string,
callback?: (event: KeyboardEvent) => void,
options?: EventListenerOptions,
): boolean {
const [isPressed, setIsPressed] = useState(false);
const callbackRef = useRef(callback);
useEffect(() => {
callbackRef.current = callback;
}, [callback]);
const handleKeyDown = useCallback(
(event: KeyboardEvent) => {
if (event.key.localeCompare(targetKey) === 0) {
setIsPressed(true);
callbackRef.current?.(event);
}
},
[targetKey],
);
const handleKeyUp = useCallback(
(event: KeyboardEvent) => {
if (event.key.localeCompare(targetKey) === 0) {
setIsPressed(false);
}
},
[targetKey],
);
useEventListener("keydown", handleKeyDown, null, options);
useEventListener("keyup", handleKeyUp);
return isPressed;
}