useKeyCombo
UI/Interaction
A React hook that detects keyboard combinations, perfect for implementing keyboard shortcuts and complex interactions.
Demo
Try these keyboard combinations:
Ctrl + S
Ctrl + Z
Ctrl + Shift + Z
Ctrl + A
Note: Make sure this window has focus for the key combinations to work.
Installation
npm install @thibault.sh/hooks
Usage
import { useKeyCombo } from '@thibault.sh/hooks/useKeyCombo';
function Editor() {
const isSaveCombo = useKeyCombo(['Control', 's']);
const isUndoCombo = useKeyCombo(['Control', 'z']);
const isRedoCombo = useKeyCombo(['Control', 'Shift', 'z']);
React.useEffect(() => {
if (isSaveCombo) {
handleSave();
} else if (isUndoCombo) {
handleUndo();
} else if (isRedoCombo) {
handleRedo();
}
}, [isSaveCombo, isUndoCombo, isRedoCombo]);
return (
<div>
<p>Available shortcuts:</p>
<ul>
<li>Ctrl + S: Save</li>
<li>Ctrl + Z: Undo</li>
<li>Ctrl + Shift + Z: Redo</li>
</ul>
{/* Editor content */}
</div>
);
}
API
Parameters
targetCombo
string[]Array of keys that make up the combination (e.g., ["Control", "Shift", "a"])
Returns
{boolean} Boolean indicating if the combination is currently active
Key Names:
- • Modifier keys: "Control", "Shift", "Alt", "Meta"
- • Single characters: "a"-"z", "0"-"9"
- • Special keys: "Enter", "Escape", "Delete", "Tab"
- • Function keys: "F1"-"F12"
Features
- ✓Order Independent
Key order doesn't matter in the combination
- ✓Multiple Modifiers
Support for combinations with multiple modifier keys
- ✓Type Safety
Full TypeScript support for key names
- ✓Cleanup
Automatically removes event listeners on unmount
Rich Text Editor Example
import { useKeyCombo } from '@thibault.sh/hooks';
import { useState } from 'react';
interface TextStyle {
isBold: boolean;
isItalic: boolean;
isUnderline: boolean;
}
function RichTextEditor() {
const [style, setStyle] = useState<TextStyle>({
isBold: false,
isItalic: false,
isUnderline: false
});
const isBoldCombo = useKeyCombo(['Control', 'b']);
const isItalicCombo = useKeyCombo(['Control', 'i']);
const isUnderlineCombo = useKeyCombo(['Control', 'u']);
React.useEffect(() => {
if (isBoldCombo) {
setStyle(prev => ({ ...prev, isBold: !prev.isBold }));
}
if (isItalicCombo) {
setStyle(prev => ({ ...prev, isItalic: !prev.isItalic }));
}
if (isUnderlineCombo) {
setStyle(prev => ({ ...prev, isUnderline: !prev.isUnderline }));
}
}, [isBoldCombo, isItalicCombo, isUnderlineCombo]);
return (
<div>
<div className="toolbar">
<button className={style.isBold ? 'active' : ''}>
Bold (Ctrl+B)
</button>
<button className={style.isItalic ? 'active' : ''}>
Italic (Ctrl+I)
</button>
<button className={style.isUnderline ? 'active' : ''}>
Underline (Ctrl+U)
</button>
</div>
<textarea
style={{
fontWeight: style.isBold ? 'bold' : 'normal',
fontStyle: style.isItalic ? 'italic' : 'normal',
textDecoration: style.isUnderline ? 'underline' : 'none'
}}
/>
</div>
);
}
Application Shortcuts Example
import { useKeyCombo } from '@thibault.sh/hooks';
import { useEffect } from 'react';
function AppShortcuts() {
const isNewFileCombo = useKeyCombo(['Control', 'n']);
const isOpenFileCombo = useKeyCombo(['Control', 'o']);
const isSaveCombo = useKeyCombo(['Control', 's']);
const isSaveAsCombo = useKeyCombo(['Control', 'Shift', 's']);
const isPrintCombo = useKeyCombo(['Control', 'p']);
const isCloseTabCombo = useKeyCombo(['Control', 'w']);
const isQuitCombo = useKeyCombo(['Control', 'q']);
useEffect(() => {
const handleShortcuts = () => {
if (isNewFileCombo) {
handleNewFile();
} else if (isOpenFileCombo) {
handleOpenFile();
} else if (isSaveAsCombo) {
// Handle Save As before Save to prevent conflict
handleSaveAs();
} else if (isSaveCombo) {
handleSave();
} else if (isPrintCombo) {
handlePrint();
} else if (isCloseTabCombo) {
handleCloseTab();
} else if (isQuitCombo) {
handleQuit();
}
};
handleShortcuts();
}, [
isNewFileCombo,
isOpenFileCombo,
isSaveCombo,
isSaveAsCombo,
isPrintCombo,
isCloseTabCombo,
isQuitCombo
]);
return (
<div className="help-panel">
<h2>Keyboard Shortcuts</h2>
<table>
<tbody>
<tr>
<td>New File</td>
<td>Ctrl + N</td>
</tr>
<tr>
<td>Open File</td>
<td>Ctrl + O</td>
</tr>
<tr>
<td>Save</td>
<td>Ctrl + S</td>
</tr>
<tr>
<td>Save As</td>
<td>Ctrl + Shift + S</td>
</tr>
<tr>
<td>Print</td>
<td>Ctrl + P</td>
</tr>
<tr>
<td>Close Tab</td>
<td>Ctrl + W</td>
</tr>
<tr>
<td>Quit</td>
<td>Ctrl + Q</td>
</tr>
</tbody>
</table>
</div>
);
}