useShortcuts Hook
Access WebShorts functionality and manage shortcuts programmatically using the useShortcuts hook.
Basic Usage
Import and use the useShortcuts hook in any component within the WebShortsProvider:
import { useShortcuts } from '@chrisnski/webshorts';
function MyComponent() {
const { shortcuts, registerShortcut, unregisterShortcut } = useShortcuts();
// Use the hook values
return <div>My Component</div>;
}
Hook Return Values
The useShortcuts hook returns an object with the following properties:
State Values
shortcuts
Array of all registered shortcuts
currentPage
Current page/route
isDialogOpen
Whether help dialog is open
debug
Debug mode status
Functions
registerShortcut
Register a new shortcut programmatically
unregisterShortcut
Remove a registered shortcut
openDialog
Open the help dialog
closeDialog
Close the help dialog
Function Examples
registerShortcut
function MyComponent() {
const { registerShortcut } = useShortcuts();
useEffect(() => {
// Register a shortcut programmatically
registerShortcut({
keys: 'CTRL + SHIFT + S',
action: () => console.log('Custom save action'),
description: 'Custom save shortcut',
page: '/editor'
});
}, [registerShortcut]);
return <div>Component with custom shortcut</div>;
}
unregisterShortcut
function MyComponent() {
const { unregisterShortcut } = useShortcuts();
const handleRemoveShortcut = () => {
// Remove a specific shortcut
unregisterShortcut('CTRL + SHIFT + S');
};
return (
<button onClick={handleRemoveShortcut}>
Remove Shortcut
</button>
);
}
openDialog / closeDialog
function HelpButton() {
const { openDialog, closeDialog, isDialogOpen } = useShortcuts();
return (
<div>
<button onClick={openDialog}>
Show Help
</button>
{isDialogOpen && (
<button onClick={closeDialog}>
Close Help
</button>
)}
</div>
);
}
State Usage
Accessing Shortcuts
function ShortcutsList() {
const { shortcuts } = useShortcuts();
return (
<div>
<h3>Available Shortcuts:</h3>
<ul>
{shortcuts.map((shortcut, index) => (
<li key={index}>
{shortcut.keys} - {shortcut.description}
</li>
))}
</ul>
</div>
);
}
Current Page Awareness
function PageSpecificComponent() {
const { currentPage } = useShortcuts();
return (
<div>
<p>Current page: {currentPage}</p>
{currentPage === '/dashboard' && (
<div>Dashboard-specific content</div>
)}
{currentPage === '/editor' && (
<div>Editor-specific content</div>
)}
</div>
);
}
Dialog State
function DialogAwareComponent() {
const { isDialogOpen, openDialog } = useShortcuts();
return (
<div>
<button
onClick={openDialog}
disabled={isDialogOpen}
>
{isDialogOpen ? 'Dialog Open' : 'Open Help'}
</button>
{isDialogOpen && (
<div className='overlay'>
Help dialog is currently open
</div>
)}
</div>
);
}
Advanced Patterns
Dynamic Shortcuts
function DynamicShortcuts() {
const { registerShortcut, unregisterShortcut } = useShortcuts();
const [isEditing, setIsEditing] = useState(false);
useEffect(() => {
if (isEditing) {
// Register editing shortcuts
registerShortcut({
keys: 'CTRL + S',
action: handleSave,
description: 'Save document'
});
registerShortcut({
keys: 'ESC',
action: () => setIsEditing(false),
description: 'Exit edit mode'
});
} else {
// Remove editing shortcuts
unregisterShortcut('CTRL + S');
unregisterShortcut('ESC');
}
}, [isEditing, registerShortcut, unregisterShortcut]);
return (
<button onClick={() => setIsEditing(!isEditing)}>
{isEditing ? 'Stop Editing' : 'Start Editing'}
</button>
);
}
Shortcut Analytics
function ShortcutAnalytics() {
const { shortcuts } = useShortcuts();
const [usageStats, setUsageStats] = useState({});
useEffect(() => {
// Track shortcut usage
const stats = shortcuts.reduce((acc, shortcut) => {
acc[shortcut.keys] = {
description: shortcut.description,
page: shortcut.page,
usageCount: 0
};
return acc;
}, {});
setUsageStats(stats);
}, [shortcuts]);
return (
<div>
<h3>Shortcut Usage Statistics</h3>
<pre>{JSON.stringify(usageStats, null, 2)}</pre>
</div>
);
}
Custom Hook
// Custom hook for specific functionality
function useEditorShortcuts() {
const { registerShortcut, unregisterShortcut } = useShortcuts();
const registerEditorShortcuts = useCallback(() => {
registerShortcut({
keys: 'CTRL + B',
action: () => document.execCommand('bold'),
description: 'Bold text'
});
registerShortcut({
keys: 'CTRL + I',
action: () => document.execCommand('italic'),
description: 'Italic text'
});
}, [registerShortcut]);
const unregisterEditorShortcuts = useCallback(() => {
unregisterShortcut('CTRL + B');
unregisterShortcut('CTRL + I');
}, [unregisterShortcut]);
return {
registerEditorShortcuts,
unregisterEditorShortcuts
};
}
// Usage
function Editor() {
const { registerEditorShortcuts, unregisterEditorShortcuts } = useEditorShortcuts();
useEffect(() => {
registerEditorShortcuts();
return () => unregisterEditorShortcuts();
}, [registerEditorShortcuts, unregisterEditorShortcuts]);
return <div>Editor with custom shortcuts</div>;
}
Error Handling
Handle potential errors when using the useShortcuts hook:
function SafeShortcutsComponent() {
const shortcutsContext = useShortcuts();
// Check if hook is available
if (!shortcutsContext) {
return <div>WebShorts not available</div>;
}
const { shortcuts, registerShortcut } = shortcutsContext;
const handleRegisterShortcut = useCallback((shortcut) => {
try {
registerShortcut(shortcut);
} catch (error) {
console.error('Failed to register shortcut:', error);
// Handle error appropriately
}
}, [registerShortcut]);
return (
<div>
<button onClick={() => handleRegisterShortcut({
keys: 'CTRL + T',
action: () => console.log('Test shortcut'),
description: 'Test shortcut'
})}>
Register Test Shortcut
</button>
</div>
);
}
Best Practices
✅ Do
- • Use the hook only within WebShortsProvider
- • Clean up shortcuts when components unmount
- • Use useCallback for function dependencies
- • Handle errors gracefully
- • Check for hook availability
- • Use descriptive shortcut descriptions
❌ Don't
- • Use the hook outside of WebShortsProvider
- • Forget to clean up registered shortcuts
- • Create infinite re-render loops
- • Ignore error handling
- • Use the hook in server components (Next.js)
- • Register duplicate shortcuts
Troubleshooting
"useShortcuts must be used within WebShortsProvider"
- • Ensure WebShortsProvider wraps your component tree
- • Check that the component is a client component (Next.js)
- • Verify the import path is correct
- • Make sure the hook is called in a React component
Shortcuts not registering?
- • Check that the shortcut object has required properties
- • Verify the keys format is correct
- • Ensure the action function is properly defined
- • Check for conflicts with existing shortcuts
- • Enable debug mode to see registration feedback
Performance issues?
- • Use useCallback for function dependencies
- • Avoid registering shortcuts in render
- • Clean up shortcuts in useEffect cleanup
- • Use React.memo for components that use the hook
- • Limit the number of shortcuts registered