function Example() { const { checkHotkeyState } = useHotkeys({ "shift + b + n": null, }); const active = checkHotkeyState("shift + b + n"); const shiftActive = checkHotkeyState("shift"); const bActive = checkHotkeyState("b"); const nActive = checkHotkeyState("n"); return ( <View animated gap={2} direction="row" backgroundColor={active ? "primary-faded" : undefined} padding={4} borderRadius="medium" > <Hotkey active={shiftActive}>Shift</Hotkey> <Hotkey active={bActive}>B</Hotkey> <Hotkey active={nActive}>N</Hotkey> </View> ); }
import { useHotkeys } from "reshaped";
useHotkeys triggers callbacks passed to it when a hotkey is pressed. It accepts an object with hotkeys defined as object keys and callbacks as object values.
You can pass a single hotkey or multiple hotkeys split by comma, which will trigger a callback when any of them is pressed. Key codes passed to the hook should match the event.key values.
// Single hotkey useHotkeys({ n: createNewTask }); // An array of hotkeys for the same callback useHotkey({ "n, t": createNewTask });
useHotkeys can be used for combinations of keys pressed together, if you separate them with a + sign. Spacing and letter casing should matter in this case, since useHotkey automatically formats all the values passed to it.
useHotkeys({ "Shift + b": switchView });
For cross-platform hotkeys, you can use a special mod key which will trigger for both cmd and ctrl keyboard keys.
useHotkeys({ "mod + b": switchView });
In case you want to prevent the default behavior of the pressed keys, you can use the event argument provided by the callback. This also mean you can prevent the default behavior only when a certain condition is met and not every time hotkey is pressed.
useHotkeys({ n: (event) => { event.preventDefault(); }, });
By default useHotkeys uses a window event handler, which means callback gets triggered anytime user pressed the hotkey. If you want your action to be triggered only for a specific element or an area of the page, you can use ref returned from the hook.
Note that a single ref for all hotkeys passed to it, which means you can assign all of them to the same element. In case you want to assign them to different elements, you can use multiple useHotkeys calls.
function Example() { const [count, setCount] = React.useState(0); const value = count > 0 ? `Value ${count}` : ""; const { ref } = useHotkeys({ ArrowUp: () => setCount((prev) => prev + 1), ArrowDown: () => setCount((prev) => Math.max(0, prev - 1)), }); return ( <TextField inputAttributes={{ ref }} placeholder="Use up and down arrow keys" value={value} /> ); }
When using with TypeScript, it is likely will ask to provide a more specific type for the DOM element you're using it with. Same as in other React hooks, you can pass that element type with a generic:
const { ref } = useHotkeys<HTMLInputElement>({ "Shift + Enter": submitForm });
If you already have a ref for the element and don't want useHotkeys to create a new one – you can pass your own ref to the useHotkeys options.
const { ref } = useHotkeys( { ArrowUp: () => setCount((prev) => prev + 1), }, [], // dependences array, mentioned below { ref: myRef } );
Additionally useHotkeys returns a checkHotkeyState function which you can use to checked if any hotkey is currently pressed. You can then use its returned boolean value to conditionally render content based on the state. It's possible to use this function result without passing a callback for the hotkey.
const { checkHotkeyState } = useHotkeys({ "Shift + b": null }); // User pressed Shift + b checkHotkeyState("Shift + b"); // true checkHotkeyState("c"); // false
Since all callbacks are binded with useEffect, they might also get cached for the further calls. Same as in effects, useHotkeys supports a dependency array:
const { count } = props; useHotkey( { b: () => console.log(count), }, [count] );
(hotkey: Record<string, (event) => void | null>) => { ref: React.RefObject<HTMLElement>, checkHotkeyState: (hotkey: string) => boolean }