A tiny (~650 B) & modern library for keybindings.
npm install tinykeystinykeys> A tiny (~650 B) & modern library for keybindings.
> See Demo
``sh`
npm install --save tinykeys
Or for a CDN version, you can use it on unpkg.com
`jswindow.tinykeys
import { tinykeys } from "tinykeys" // Or using the CDN version
tinykeys(window, {
"Shift+D": () => {
alert("The 'Shift' and 'd' keys were pressed at the same time")
},
"y e e t": () => {
alert("The keys 'y', 'e', 'e', and 't' were pressed in order")
},
"$mod+([0-9])": event => {
event.preventDefault()
alert(Either 'Control+${event.key}' or 'Meta+${event.key}' were pressed)`
},
})
Alternatively, if you want to only create the keybinding handler, and register
it as an event listener yourself:
`js
import { createKeybindingsHandler } from "tinykeys"
let handler = createKeybindingsHandler({
"Shift+D": () => {
alert("The 'Shift' and 'd' keys were pressed at the same time")
},
"y e e t": () => {
alert("The keys 'y', 'e', 'e', and 't' were pressed in order")
},
"$mod+KeyD": event => {
event.preventDefault()
alert("Either 'Control+d' or 'Meta+d' were pressed")
},
})
window.addEventListener("keydown", handler)
`
If you're using tinykeys within a component, you should also make use of the
returned unsubscribe() function.
`js
import { useEffect } from "react"
import { tinykeys } from "tinykeys"
function useKeyboardShortcuts() {
useEffect(() => {
let unsubscribe = tinykeys(window, {
// ...
})
return () => {
unsubscribe()
}
})
}
`
's and code'sKeybindings will be matched against
KeyboardEvent.key
andKeyboardEvent.code
which may have some names you don't expect.
| Windows | macOS | key | code |Command
| ------------- | --------------- | ------------- | ------------------------------ |
| N/A | / ⌘ | Meta | MetaLeft / MetaRight |Alt
| | Option / ⌥ | Alt | AltLeft / AltRight |Control
| | Control / ^ | Control | ControlLeft / ControlRight |Shift
| | Shift | Shift | ShiftLeft / ShiftRight |Space
| | Space | N/A | Space |Enter
| | Return | Enter | Enter |Esc
| | Esc | Escape | Escape |1
| , 2, etc | 1, 2, etc | 1, 2, etc | Digit1, Digit2, etc |a
| , b, etc | a, b, etc | a, b, etc | KeyA, KeyB, etc |-
| | - | - | Minus |=
| | = | = | Equal |+
| | + | + | Equal\* |
Something missing? Check out the key logger on the
demo website
> _\* Some keys will have the same code as others because they appear on the
> same key on the keyboard. Keep in mind how this is affected by international
> keyboards which may have different layouts._
In some instances, tinykeys will alias keys depending on the platform to
simplify cross-platform keybindings on international keyboards.
On Windows, on many non-US standard keyboard layouts, there is a key named
Alt Gr or AltGraph in the browser, in some browsers, pressing Control+AltAltGraph
will report as being pressed instead.
Similarly on macOS, the Alt (Option) key will sometimes be reported as theAltGraph key.
Note: The purpose of the Alt Gr key is to type "Alternate Graphics" so youevent.code
will often want to use the (KeyS) for letters instead ofevent.key (S)
`jsControl+Alt+S
tinykeys(window, {
"Control+Alt+KeyS": event => {
// macOS: or Control+AltGraph+SControl+Alt+S
// Windows: or Control+AltGraph+S or AltGraph+SMeta+Alt+S
},
"$mod+Alt+KeyS": event => {
// macOS: or Meta+AltGraph+SControl+Alt+S
// Windows: or Control+AltGraph+S or AltGraph+S`
},
})
Keybindings are made up of a _sequence_ of _presses_.
A _press_ can be as simple as a single _key_ which matches against
KeyboardEvent.code
and
KeyboardEvent.key
(case-insensitive).
`jsevent.key
// Matches :event.code
"d"
// Matches: :`
"KeyD"
Presses can optionally be prefixed with _modifiers_ which match against any
valid value to
KeyboardEvent.getModifierState().
`js`
"Control+d"
"Meta+d"
"Shift+D"
"Alt+KeyD"
"Meta+Shift+D"
There is also a special $mod modifier that makes it easy to support cross
platform keybindings:
- Mac: $mod = Meta (⌘)$mod
- Windows/Linux: = Control
`js`
"$mod+D" // Meta/Control+D
"$mod+Shift+D" // Meta/Control+Shift+D
Alternatively, you can use parenthesis to use case-sensitive regular expressions
to match multiple keys.
`js`
"$mod+([0-9])" // $mod+0, $mod+1, $mod+2, etc...
// equivalent regex: /^[0-9]$/
Keybindings can also consist of several key presses in a row:
`js`
"g i" // i.e. "Go to Inbox"
"g a" // i.e. "Go to Archive"
"ArrowUp ArrowUp ArrowDown ArrowDown ArrowLeft ArrowRight ArrowLeft ArrowRight B A"
Each press can optionally be prefixed with modifier keys:
`js`
"$mod+K $mod+1" // i.e. "Toggle Level 1"
"$mod+K $mod+2" // i.e. "Toggle Level 2"
"$mod+K $mod+3" // i.e. "Toggle Level 3"
Each press in the sequence must be pressed within 1000ms of the last.
You can use the parseKeybinding method to get a structured representation of a
keyboard shortcut. It can be useful when you want to display it in a fancier way
than a plain string.
`js
import { parseKeybinding } from "tinykeys"
let parsedShortcut = parseKeybinding("$mod+Shift+K $mod+1")
`
Results into:
`js`
[
[["Meta", "Shift"], "K"],
[["Meta"], "1"],
]
You can configure the behavior of tinykeys in a couple ways using a third
options parameter.
`js`
tinykeys(
window,
{
M: toggleMute,
},
{
event: "keyup",
capture: true,
},
)
Valid values: "keydown", "keyup"
Key presses will listen to this event (default: "keydown").
> Note: Do not pass "keypress", it is deprecated in browsers.
Keybinding sequences will wait this long between key presses before cancelling
(default: 1000).
> Note: Setting this value too low (i.e. 300`) will be too fast for many of
> your users.