Desktop-grade keyboard interactions for modern React applications.
Overview · Installation · Quick Start · Frameworks · Documentation · Contributing
Desktop-grade keyboard ergonomics for React apps:
- Mnemonics: Platform-aware accelerators via
&syntax (<button>&File</button>) with semantic underlines (Alt+Fon Windows/Linux,⌘Fon macOS). - Hotkeys: Declarative element bindings (
<input hotkey="mod+k" />). - Modal Scoping: Blocks background shortcuts when dialogs, sheets, or palettes are active.
- Overlay Hints: Floating keycap badges on demand (
<KeyboundOverlay />). - Hooks API:
useMnemonicanduseHotkeyfor dynamic labels and i18n without a build step. - Tiny Footprint: ~7.9 KB gzipped runtime. React peer dependencies only. Zero runtime dependencies.
- SSR Safe: Listeners attach in client effects; Next.js, Vite, and Remix compatible.
npm install react-keyboundimport { KeyboundProvider } from 'react-keybound';
import type {} from 'react-keybound/jsx';
export function App({ children }: { children: React.ReactNode }) {
// mnemonicModifier="auto" defaults to Alt on Windows/Linux and ⌘ (mod) on macOS/iPadOS
return <KeyboundProvider>{children}</KeyboundProvider>;
}With the compiler enabled:
export function Toolbar() {
return (
<nav>
{/* Alt+F / ⌘F triggers File, Alt+E / ⌘E triggers Edit */}
<button onClick={() => openMenu('file')}>&File</button>
<button onClick={() => openMenu('edit')}>&Edit</button>
{/* Mod+K (⌘K on macOS, Ctrl+K on Windows/Linux) focuses search */}
<input hotkey="mod+k" placeholder="Search (⌘K)..." />
</nav>
);
}Syntax:
&Save→ Save (Alt+Son Windows/Linux,⌘Son macOS)E&xport→ Export (Alt+Xon Windows/Linux,⌘Xon macOS)Save && &Close→ Save & Close (Alt+C/⌘C,&&for literal&)
By default, <KeyboundProvider> sets mnemonicModifier="auto":
- Windows & Linux: Uses
Alt(Alt+S). - macOS & iPadOS: Uses
mod/Command(⌘S).
On Apple hardware, the Option (⌥) key is an alternate character and dead-key composer. Pressing Option+S outputs ß, and Option+E produces Dead. Under Keybound's pure semantic matching (KeyboardEvent.key), these glyphs do not match ASCII letters. Using mod (⌘) keeps mnemonics accessible as clean semantic characters.
If you want to avoid browser-reserved shortcuts on Mac (e.g. ⌘W or ⌘T), you can map mac to Control (⌃), which is completely free from browser intercepts:
<KeyboundProvider
mnemonicModifier={{
mac: 'ctrl', // ⌃S on macOS
windows: 'alt', // Alt+S on Windows
linux: 'alt', // Alt+S on Linux
}}
>
{children}
</KeyboundProvider>For dynamic strings or runtime translations:
import { useMnemonic, useHotkey } from 'react-keybound';
function ActionButton({ text, onAction }: { text: string; onAction: () => void }) {
const { label, triggerProps } = useMnemonic<HTMLButtonElement>(text, { onAction });
return <button {...triggerProps}>{label}</button>;
}
function GlobalSearch() {
const { triggerProps } = useHotkey<HTMLInputElement>('mod+k');
return <input {...triggerProps} placeholder="Search..." />;
}import { withKeybound } from 'react-keybound/next';
export default withKeybound(
{},
{
components: ['Button', 'Link'],
},
);import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import keybound from 'react-keybound/vite';
export default defineConfig({
plugins: [keybound(), react()],
});- Clone the repository:
git clone https://github.com/Eggwite/keybound.git cd keybound - Install dependencies:
npm ci
- Start the dev playground:
npm run dev
- Verify changes:
npm run check npm run format:check
See CONTRIBUTING.md, CODE_OF_CONDUCT.md, and AGENTS.md.