⌨️ A tiny keyboard shortcut handling library.
- Pocket-sized – library size is less than 600 bytes (~350 bytes gzipped!)
- Minimal – pass a
callback
function=>
get results. - Specialized – only handles key combinations with at least one or more modifier keys pressed and at most one regular key (read more)
- Framework-agnostic – can be plugged on any standard
KeyboardEvent
listener (keyup
,keydown
,keypress
, etc.)
- Declaratively listen for shortcut events
- Key combination input field for user-friendly shortcut configuration
- Handle simple or complex shortcut UIs with a standardized format
Example
import combi from 'combi'
const onShortcut = combi((shortcut, keyEvent) => {
console.log(shortcut) // -> 'ctrl+z'
})
window.addEventListener('keydown', onShortcut)
npm install --save combi
Alternatively, you can download and/or import it from unpkg.com/combi as an ES or UMD module.
import combi from 'https://unpkg.com/combi/dist/combi.es.js'
<!-- This adds `combi` to the global context (`window`) -->
<script src="https://unpkg.com/combi/dist/combi.umd.js"></script>
You can find the library on window.combi
combi
takes a handler function as an argument. This handler function should take two arguments. The first one: the keyboard shortcut that has been pressed. The second one: the original keyboard event. You can match these shortcuts however you want.
import combi from 'combi'
const onShortcut = combi((shortcut) => {
switch ((shortcut, event)) {
case 'meta+s':
case 'ctrl+s':
event.preventDefault()
action('save')
break
case 'shift+meta+z':
case 'ctrl+y':
event.preventDefault()
action('redo')
break
case localStorage.getItem('shortcut'):
event.preventDefault()
action('custom-action')
break
default:
// do nothing.
}
})
window.addEventListener('keydown', onShortcut)
You can use combi
to create custom input fields for specifying key combinations. Useful when building apps with configurable keyboard shortcuts.
import combi from 'combi'
// pass `true` as second argument to call preventDefault() when a combination is used
const onShortcut = combi((combination, event) => {
event.target.value = combination
localStorage.setItem('shortcut', combination)
}, true)
const inputElement = document.querySelector('#shortcut-input')
inputElement.addEventListener('keydown', onShortcut)
combi(callback: Function, preventDefault?: Boolean)
A function that handles shortcuts, that looks like this:
(shortcut: String, event: KeyboardEvent) => any
shortcut {String}
- keyboard shortcut that has been pressed (e.g. shift+meta+x
, ctrl+y
)
event {KeyboardEvent}
- the original KeyboardEvent
passed to combi
by the event listener
Whether combi
should always call .preventDefault()
when receiving a keyboard event. Defaults to false
These are the modifiers combi
supports. Shortcuts detected will always be parsed in this order:
- ctrl
- alt
- shift
- meta
- Command key (⌘) on macOS
- Windows key (⊞) on Windows (note: using
meta
on Windows is highly discouraged for non-system shortcuts)
In order to maintain combi
as simple as possible, while enabling the most common and standard use cases, some rules are in place:
- Only key combinations of two or more keys are allowed, with the following conditions:
- at least one or more modifiers (ctrl, shift, alt, etc.)
- at most one regular key (a-z, 0-9, -, +, [, ], \, etc.)
- Example: shift+k+z won't work
- Key combinations are represented as a string concatenation of modifier keys and an (optional, if the combination is of more than two ) regular key in the following normative order: ctrl
+
alt+
shift+
meta+
somekey - All non-modifier keys are lowercased versions of
KeyboardEvent.code
with the wordsKey
andDigit
removed- Examples:
KeyA
becomesa
Digit0
becomes0
BracketLeft
becomesbracketleft
- Examples:
Note: These considerations are not arbitrary. Most of them are derived from the following guidelines:
- Keyboard - Human Interface Guidelines - Apple
- Guidelines for Keyboard User Interface Design - Microsoft
- Keyboard | Microsoft Docs
- Character Key Shortcuts - Web Content Accessibility Guidelines (WCAG) 2.1
Something does not work as expected or perhaps you think this project needs a feature? Please open an issue using GitHub issue tracker.
Make sure that an issue pointing out your specific problem does not exist already. Please be as specific and straightforward as possible.
Pull Requests (PRs) are welcome! You should follow the same basic stylistic conventions as the original code.
Make sure that a pull request solving your specific problem does not exist already. Your changes must be concise and focus on solving a discrete problem.
Copyright (c) 2018 Kristian Muñiz