@keybindy/core
Version:
A lightweight and framework-agnostic keyboard shortcut manager for web apps. Define, register, and handle keybindings with ease.
486 lines (325 loc) β’ 13.9 kB
Markdown
# Keybindy
**Keybindy** is a lightweight, fast, and framework-agnostic TypeScript library for managing keyboard shortcuts in JavaScript applications. With a small footprint and zero dependencies, Keybindy makes it easy to register, manage, and scope keyboard shortcuts in any environment β whether you're building with vanilla JavaScript, Vue, Svelte, or another framework.
The `@keybindy/core` package is the foundation of the Keybindy ecosystem, providing all the logic for keyboard shortcut management. For React developers, the optional `@keybindy/react` package offers seamless integration.
[](https://www.npmjs.com/package/@keybindy/core)
[](https://opensource.org/licenses/MIT)
## π Why **Keybindy**?
Keyboard shortcuts are essential for productivity and a smooth user experience β but managing them across components, contexts, and frameworks can quickly become a nightmare.
Thatβs where **Keybindy** comes in.
#### Why not other libraries?
Other shortcut libraries often come with:
- Framework lock-ins (React-only, etc.)
- Extra dependencies that bloat your bundle
- Complex APIs and awkward scope handling
- Larger file sizes that slow down performance
#### What makes Keybindy different?
**Keybindy** is a blazing-fast, ultra-lightweight **TypeScript-first** solution for handling keyboard shortcuts.
Itβs designed to be:
- **Tiny & dependency-free** β approximately **2KB** gzipped
- **Framework-agnostic** β works with **Vanilla JS, React, Vue, Svelte**, and beyond
- **Simple yet powerful** β clean APIs to register, scope, and manage shortcuts effortlessly
- **Tree-shakeable** β only includes what you actually use
- **Side-effect free** β making it ideal for modern builds
Whether you're building a single-page app, a design tool, or a productivity suite β **Keybindy** gives you total control over keyboard interactions without the baggage.
### Use Cases
- Registering global shortcuts (e.g., `Ctrl+S` for saving)
- Managing scoped shortcuts for modals, editors, or UI sections
- Creating keyboard-driven UIs for accessibility and power users
- Enhancing web games and interactive tools with custom bindings
## Features
- **β
Global and Scoped Shortcuts** β Define app-wide or context-specific keys
- **πΊ Multi-Key Combos** β Full support for combinations like Ctrl+Shift+K
- **β»οΈ Key Alias Normalization** β Smart matching of `cmd β meta`, `ctrl (left) | ctrl (right) β ctrl`, etc.
- **π§Ό Prevent Default Behavior** β Easily block native browser actions
- **β‘ Zero Dependencies** β Lightweight and fast
- **π§ Framework Agnostic** β Works with any frontend stack
- **π Type-Safe** β Written in TypeScript with full .d.ts support
- **π CDN Friendly** β Use in plain HTML projects with a simple script tag
- **π Custom Event Hooks** β Emit key events for custom behavior and extensions
## Installation
Install the core package using your preferred package manager:
```bash
# npm
npm install @keybindy/core
# yarn
yarn add @keybindy/core
# bun
bun add @keybindy/core
```
Or use via CDN (URL coming soon):
```html
<script src="https://unpkg.com/@keybindy/core@1.1.4/dist/keybindy.min.js"></script>
```
## Getting Started
### Initialization
```ts
// With import
import ShortcutManager from '@keybindy/core';
const manager = new ShortcutManager();
// With CDN
const manager = new Keybindy();
```
### Register shortcuts
```ts
// Register "Enter" to submit a form in the "modal" scope
manager.register(
['Enter'],
() => {
console.log('Submitting modal form...');
},
{ scope: 'modal', preventDefault: true }
);
// Activate the modal scope (e.g., when modal opens)
manager.setActiveScope('modal');
```
### Supported methods
#### **`start`**
Starts the manager manually. This is usually not required, as the manager starts automatically on instantiation.
##### Example
```ts
manager.start();
```
#### **`register`**
Registers a new shortcut.
| Parameter | Type | Required | Description |
| --------- | ----------------- | -------- | ------------------------------------------------------- |
| `keys` | `Keys[]` | β
| Keys to bind (e.g., ["ctrl", "shift", "k"]) |
| `handler` | `ShortcutHandler` | β
| Callback to execute when the shortcut is triggered. |
| `options` | `ShortcutOptions` | β | Optional config (scope, preventDefault, metadata, etc.) |
##### Example
```ts
manager.register(
['ctrl', 'shift', 'k'],
() => {
console.log('Triggered Ctrl+Shift+K');
},
{
preventDefault: true,
scope: 'modal',
sequential: true,
sequenceDelay: 1000,
data: {
// metadata
label: 'Ctrl+Shift+K',
description: 'Submit form',
},
}
);
```
#### **`ShortcutOptions`**
The `options` object allows you to customize the behavior of a shortcut.
| Option | Type | Default | Description |
| ---------------- | --------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `scope` | `string` | `"global"` | The scope in which the shortcut is active. |
| `preventDefault` | `boolean` | `false` | If `true`, calls `event.preventDefault()` to block the browser's default action. |
| `sequential` | `boolean` | `false` | If `true`, treats the key combination as a sequence (e.g., `G` then `H`). |
| `sequenceDelay` | `number` | `1000` | The maximum time (in ms) between key presses for a sequential shortcut. |
| `triggerOn` | `string` | `"keydown"` | For simultaneous shortcuts, specifies whether to trigger on `"keydown"` or `"keyup"`. |
| `hold` | `boolean` | `false` | If `true`, treats the shortcut as a "hold" action. The handler will be called on both key down and key up with a `state` argument (`"down"` or `"up"`). |
| `repeat` | `boolean` | `false` | If `true`, allows the shortcut to be repeatedly fired when the key is held down. By default, shortcuts only fire once. |
| `data` | `object` | `{}` | An object for any custom metadata you want to associate with the shortcut, useful for building features like cheat sheets. |
#### **`unregister`**
Removes a previously registered shortcut.
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ------------------- |
| `keys` | `Keys[]` | β
| The keys to unbind. |
##### Example
```ts
manager.unregister(['ctrl', 'shift', 'k']);
```
#### **`enable / disable / toggle`**
Enables, disables, or toggles a shortcut on or off.
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ----------- |
| `keys` | `Keys[]` | β
| |
##### Example
```ts
manager.enable(['ctrl', 's']);
manager.disable(['ctrl', 's']);
manager.toggle(['ctrl', 's']);
```
#### **`enableAll / disableAll`**
Enable or disable all shortcuts β globally or within a specific scope.
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | -------------------------------------- |
| `scope` | `string` | β | scope to enable/disable all shortcuts. |
##### Example
```ts
manager.enableAll(); // Global
manager.enableAll('modal'); // Scoped
manager.disableAll(); // Global
manager.disableAll('modal'); // Scoped
```
#### **`getCheatSheet`**
Returns a list of all registered shortcuts. Optionally scoped.
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ------------------------- |
| `scope` | `string` | β | scope to get cheat sheet. |
##### Example
```ts
manager.getCheatSheet();
```
### Scope Management
#### **`getScopes`**
Returns all registered scopes.
##### Example
```ts
manager.getScopes();
```
#### **`getActiveScope`**
Returns the currently active scope.
##### Example
```ts
manager.getActiveScope();
```
#### **`setActiveScope`**
Sets the current active scope.
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ----------------- |
| `scope` | `string` | β
| The scope to set. |
##### Example
```ts
manager.setActiveScope('modal');
```
#### **`isScopeActive`**
Checks if a specific scope is currently active.
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ------------------- |
| `scope` | `string` | β
| The scope to check. |
##### Example
```ts
manager.isScopeActive('modal');
```
#### **`getScopesInfo`**
Returns information about all scopes or a specific one.
| Parameter | Type | Required | Description |
| --------- | -------- | -------- | ------------------ |
| `scope` | `string` | β | scope to get info. |
##### Example
```ts
manager.getScopesInfo();
manager.getScopesInfo('modal');
```
#### **`pushScope / popScope / resetScope`**
Manage the scope stack.
##### Example
```ts
manager.pushScope('modal');
manager.popScope();
manager.resetScope();
```
#### **`destroy`**
Fully destroys the manager instance and removes all bindings.
##### Example
```ts
manager.destroy();
```
#### **`clear`**
Clears the internal state without destroying the instance.
##### Example
```ts
manager.clear();
```
### Event
#### **`onTyping`**
Listen for every typed key. Useful for custom behavior or analytics.
##### Example
```ts
manager.onTyping(({ key, event }) => {
console.log(`Key typed: ${key}`, event);
});
```
## Theories & Concepts
`@keybindy/core` is designed to provide a flexible and powerful foundation for keyboard shortcut management. This section outlines the core ideas and keybinding types supported by the library.
#### Keybinding Types Supported
We support three primary types of key combinations:
##### 1. Sequential Key Combos
These are keybindings where the user presses keys one after another, like:
```txt
g β h
```
This style is commonly seen in editors like Vim or platforms like GitHub, where pressing g followed by h might trigger navigation (e.g., go to the homepage).
- Supported out of the box
- Timeout configurable between key presses.
- `sequenceDelay:` Sets the max time (in ms) allowed between keys.
- Sequence memory is reset on timeout or invalid input
```ts
manager.register(
...,
...,
{
sequential: true,
sequenceDelay: 1000
});
```
##### 2. Simultaneous Key Combos
These are triggered when multiple keys are held down together, like:
```txt
Ctrl + K
Meta + Shift + P
```
Perfect for standard "shortcut-style" commands that fire instantly when all keys are down at once.
```ts
manager.register(
...,
...
);
```
##### 3. Holdable Key Combos
These are special shortcuts that trigger on both key down and key up. They are ideal for actions that need to persist while a key is held, such as a "push-to-talk" feature.
- **Trigger on Down & Up**: The handler receives a `state` argument (`"down"` or `"up"`).
- **Stateful**: The manager tracks the active hold state.
```ts
manager.register(
['Ctrl', 'Shift'],
(event, state) => {
console.log(`Mic is ${state === 'down' ? 'on' : 'off'}`);
},
{ hold: true }
);
```
#### Alias Support
`@keybindy/core` supports aliasing of platform-specific key variations, so your shortcuts work consistently across different operating systems and keyboard layouts:
- `ctrl (left)` / `ctrl (right)` β `ctrl`
- `shift (left)` / `shift (right)` β `shift`
- `alt (left)` / `alt (right)` β `alt`
- `meta (left)` / `meta (right)` β `meta`
- `cmd` β `meta`
- `enter` / `numpad enter` β `enter`
## Ecosystem
Keybindy has modular packages for different platforms. Each package is built to work seamlessly with the core engine.
| Package | Description |
| -------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| [`@keybindy/core`](https://npmjs.com/package/@keybindy/core) | The core JavaScript library. Framework-agnostic, fully typed, and tree-shakable. |
| [`@keybindy/react`](https://npmjs.com/package/@keybindy/react) | React bindings with hooks and components for easy integration. |
| _Coming Soon_ | Stay tuned! |
## Contributing
PRs, issues, and ideas are welcome! See [CONTRIBUTING.md](./CONTRIBUTING.md) for details.
If you're adding a new framework integration (like Vue or Svelte), feel free to open a draft PR β we'd love to collaborate.
> _Might be new in the shortcut game, but Keybindyβs here to change the frame β fast, flexible, and ready to claim. π―_