Keyboard Shortcuts
Relevant source files
The following files were used as context for generating this wiki page:The Keyboard Shortcuts feature provides a set of hotkeys to improve user efficiency and navigation within the application's main dashboard. This functionality is primarily managed by the useKeyboardShortcuts custom React hook, which listens for global keydown events and triggers corresponding actions.
The system is designed to be context-aware, disabling shortcuts when the user is typing in input fields, text areas, or rich text editors to prevent conflicts. A dedicated help modal, accessible via the ? key, lists all available shortcuts for the user.
Core Logic: useKeyboardShortcuts Hook
The heart of the feature is the useKeyboardShortcuts.ts hook. It encapsulates all logic for handling key presses, managing state, and executing callbacks provided by the consuming component.
Sources: services/web/src/hooks/useKeyboardShortcuts.ts
Hook Interface
The hook is configured through the KeyboardShortcutsOptions interface, which defines the data and callback functions required for its operation.
| Prop | Type | Description |
|---|---|---|
messages | { id: string }[] | An array of message objects, used to calculate the next/previous message index. |
selectedMessageId | string | undefined | The ID of the currently selected message. |
onSelectMessage | (index: number) => void | Callback to select a message by its index in the messages array. |
onDeleteMessage | () => void (optional) | Callback to delete the currently selected message. |
onMarkUnread | () => void (optional) | Callback to mark the selected message as unread. |
onReply | () => void (optional) | Callback to open the reply/compose modal for the selected message. |
onRefresh | () => void (optional) | Callback to refresh the message list. |
onFocusSearch | () => void (optional) | Callback to focus the search input field. |
onShowHelp | () => void (optional) | Callback to display the keyboard shortcuts help modal. |
onBack | () => void (optional) | Callback for 'back' or 'close' actions, like closing a detail view. |
enabled | boolean (optional) | A flag to enable or disable the hook's event listener. Defaults to true. |
Sources: services/web/src/hooks/useKeyboardShortcuts.ts:3-19
Event Handling Flow
The hook attaches a keydown event listener to the window object. The handleKeyDown callback contains the primary logic, which is memoized using useCallback for performance.
This diagram illustrates the logic flow when a key is pressed.
A critical feature is preventing shortcuts from firing while a user is typing. The hook checks if the event target is an INPUT, TEXTAREA, or a contentEditable element (like the Quill editor). If so, it ignores all shortcuts except for Escape, which is used to blur the active element.
Sources: services/web/src/hooks/useKeyboardShortcuts.ts:31-39, services/web/src/components/Editor.tsx:11
Shortcut Definitions
The available shortcuts and their descriptions are defined in the KEYBOARD_SHORTCUTS constant. This array is exported from the hook file and consumed by the KeyboardShortcutsHelp component to render the help modal.
| Key(s) | Action (Vietnamese) | Action (English Translation) |
|---|---|---|
j / ↓ | Email tiếp theo | Next email |
k / ↑ | Email trước đó | Previous email |
o / Enter | Mở email | Open email |
e / Delete | Xóa email | Delete email |
Shift + U | Đánh dấu chưa đọc | Mark as unread |
r | Trả lời | Reply |
Shift + R | Làm mới | Refresh |
/ | Tìm kiếm | Search |
? | Hiện trợ giúp | Show help |
Esc | Đóng / Quay lại | Close / Go back |
Sources: services/web/src/hooks/useKeyboardShortcuts.ts:133-144
Integration and Usage
Dashboard Integration
The Dashboard.tsx component is the primary consumer of the useKeyboardShortcuts hook. It initializes the hook and provides it with the necessary state and callback functions to manipulate the UI.
The following diagram shows the interaction between the user, the Dashboard, and the hook.
The enabled prop is used to dynamically disable the shortcuts, for instance, when a modal like ComposeModal or KeyboardShortcutsHelp is open.
// services/web/src/pages/Dashboard.tsx:517-518
useKeyboardShortcuts({
// ... other options
enabled: !showCompose && !showKeyboardHelp,
});
Sources: services/web/src/pages/Dashboard.tsx:518, services/web/src/components/ComposeModal.tsx:15
Help Modal (KeyboardShortcutsHelp)
The KeyboardShortcutsHelp component is a simple presentational component that displays the list of available shortcuts. It is triggered by the onShowHelp callback from the hook, which is typically bound to the ? key.
The component imports the KEYBOARD_SHORTCUTS constant and maps over it to render each shortcut and its corresponding action in a structured layout.
// services/web/src/components/KeyboardShortcutsHelp.tsx:28-35
<div className="space-y-2">
{KEYBOARD_SHORTCUTS.map(({ key, action }) => (
<div key={key} className="flex justify-between items-center py-2 border-b border-border last:border-0">
<span className="text-sm text-text-main">{action}</span>
<kbd className="px-2 py-1 bg-bg border border-border rounded text-xs font-mono text-muted">
{key}
</kbd>
</div>
))}
</div>
Sources: services/web/src/components/KeyboardShortcutsHelp.tsx:28-35, services/web/src/hooks/useKeyboardShortcuts.ts:133
Summary
The keyboard shortcuts system is a well-encapsulated feature centered around the useKeyboardShortcuts hook. This design promotes reusability and separation of concerns, allowing the Dashboard component to provide the "how" (the actions) while the hook manages the "when" (the key presses and context). The system enhances user experience by providing efficient, keyboard-driven navigation and actions throughout the main application interface.