useHotkeys API
Function signature:
function useHotkeys<T extends Element>(
keys: string,
callback: (event: KeyboardEvent, handler: HotkeysEvent) => void,
options: Options = {},
deps: any[] = []
): React.MutableRef<T | null>
Arguments
keys
keys: string
Set the keystrokes we want the hook to listen to. We can use single or multiple keys, modifier combinations, etc. See this guide of the underlying hotkeys package for all possible shortcuts.
Listening to all keys
useHotkeys('*', (_, handler) => alert(handler.key))
Using modifiers
useHotkeys('ctrl+s, shift+w', () => alert('We\'re using modifiers now!'))
The alt modifier has its own special handling. To check if an altKey was pressed we need to listen to all keys and check for the alt modifier in the event object:
useHotkeys('*', e => {
console.log('Pressed alt modifier', e.altKey);
console.log('Pressed key', e.key)
})
This will change in the upcoming v4.
Using F keys
useHotkeys('f5', () => alert('F5 was pressed'))
Using multiple keys
useHotkeys('w, a, s, d', () => alert('Player moved!'))
If we use a combination of possible keys that use the same hook, we can use handler.key
to check which key the user
pressed.
useHotkeys('ctrl+a, shift+b, r, f', (_, handler) => {
switch (handler.key) {
case 'ctrl+a': alert('You pressed ctrl+a!');
break;
case 'ctrl+b': alert('You pressed ctrl+b!');
break;
case 'r': alert('You pressed r!');
break;
case 'f': alert('You pressed f!');
break;
}
})
callback
callback: (event: KeyboardEvent, handler: HotkeysEvent) => void
Gets executed when the defined keystroke gets hit by the user. event
holds the browsers keyboard event, handler
passes
some additional information to handle the pressed key.
event
The browsers native keyboard event that gets created when the user hits a key. For a thorough documentation of this event check out the MDN Web Docs.
handler
The handler
holds information about the pressed key. In general, we should only need this object to handle our keyboard
events.
The most important property of the handler
object is the key
prop:
key: string
- This will hold the pressed keystroke. So if we use multiple possible keystroke combinations for the same callback we can use this property to check which specific keystroke was pressed.
There are more properties attached to the handle that currently don't get populated with values. So we can safely ignore those.
The callback we pass into the hook gets memoised, so every variable we reference inside the callback must be added to the dependencies array, otherwise we will get stale values. For more on memoisation in the context of React hooks read this nice article.
options
We can extensively configure how the hook behaves by passing it an options
object. Below are all properties that the
object takes.
// Default values
const options = {
filter: undefined,
filterPreventDefault: true,
enableOnTags: [],
enabled: true,
splitKey: '+',
keyup: undefined,
keydown: true
};
// Type Definitions
type AvailableTags = 'INPUT' | 'TEXTAREA' | 'SELECT';
type Options = {
enabled?: boolean;
filter?: (event: KeyboardEvent) => boolean;
filterPreventDefault?: boolean;
enableOnTags?: AvailableTags[];
enableOnContentEditable?: boolean;
splitKey?: string;
keyup?: boolean;
keydown?: boolean;
};
Properties
filter
filter: (event: KeyboardEvent) => boolean // default: undefined
Pass a function filter
to determine if the callback should get triggered. Return false
to prevent the execution
of the callback and true
to allow the callback to be triggered.
filterPreventDefault
filterPreventDefault: boolean // default: true
This flag determines if the default browser behavior should be prevented if the given filter
function returns false
and
therefore prevents the execution of the callback. true
is the default value, so each time the filter blocks the callback
execution, the browser won't proceed with its default behavior. Setting this to false
will allow the browser to proceed
with the default behavior.
A good example for this behavior is the override of command+s
, which normally triggers a save page dialog
inside the browser.
useHotkeys('command+s', someCallback, {
// This will allow the browser to show the save page dialog.
// Setting it to true will prevent that.
filterPreventDefault: false,
filter: () => false
});
enabledOnTags
enabledOnTags: string[] // default: undefined
Normally we do not want a hotkey being triggered while a user types something into an input field. In some cases however this might desirable. We can enable the callback trigger for an input tag using the following values:
INPUT
, TEXTAREA
, SELECT
enabled
enabled: boolean // default: true
Setting this to false
prevents the hook from doing anything.
splitKey
splitKey: string // default: "+"
Specifies the key that is used to combine multiple hotkeys into keystrokes. The default value is +
, so shift+a
triggers
when the user presses the "shift" key and the "a" key.
Setting the splitKey
to -
to listen to a keystroke like +
or shift-+
doesn't work. There is a bug in the implementation
of the underlying hotkeys package that React Hotkeys Hook leverages. See this issue
and this issue.
This problem will be addressed in the upcoming Version 4.
keyup
keyup: boolean // default: false
Set this to true
if we want the hook to trigger our callback on the browsers keyUp
event.
keydown
keydown: boolean // default: true
Set this to true
if we want the hook to trigger our callback on the browsers keyDown
event. This is the default behavior.
keydown
and keyup
If we set keyup
to true
and don't set the keydown
prop (leaving the default), React Hotkeys Hook will assume
that we want to only listen to the browsers keyUp
event.
If we in fact want the callback to get triggered by both events, we have to explicitly set both properties like so:
useHotkeys('a', () => someCallback, {
keydown: true,
keyup: true
})
deps
deps: any[] // default: []
The dependency array lets we use the hook just like Reacts internal useCallback
or useMemo
hook. This where our
dependencies of the callback live. If for example our callback actions depend on a referentially unstable value or a
value that will change over time, we should add this value to our deps array. Check out the
documentation part
for examples.
Return value
React.MutableRef<T | null>
The useHotkeys
hook returns a React ref. This ref by default holds the value of null
. We can use this ref to only
trigger the hotkeys if a specific element has been focused by the user.
Elements that don't provide any native interactivity like <div>
, <span>
, <p>
, etc. cannot receive a focus by default.
If we want to use <div>
tags instead of the <button>
tags in the example above we have to provide a tabIndex
prop
to the tag. This way the focusing will work with all tags.
Function signature overloads
There is a common case where we want to pass dependencies to the hook but no options object. Normally we would need to write that out like this:
useHotkeys('a', () => someDependency, undefined, [someDependency]);
To streamline this use case the hook accepts function overloads. With this we can pass a dependency array as the third argument instead of the fourth.
function useHotkeys<T extends Element>(
keys: string,
callback: (event: KeyboardEvent, handler: HotkeysEvent) => void,
deps: any[] = []
): React.MutableRef<T | null>
So we are able to use the hook like this:
useHotkeys('a', () => someDependency, [someDependency]);