Pierre Awaragi1k downloadsDisplay a searchable cheatsheet of all your Obsidian hotkeys.
A live, searchable reference card for all your Obsidian keyboard shortcuts — opened instantly from the ribbon or command palette, with optional tracking of which ones you actually use.
Obsidian's built-in hotkey settings show a flat alphabetical list of 250+ commands. This plugin gives you a visual overview instead: a newspaper-style multi-column layout with every shortcut you have assigned, complete with Cmd, Shift, Option, Ctrl key badges rendered for your OS. Turn on usage tracking and it'll also show you how often each one gets used.

b to find all Cmd B, Cmd Shift B, etc.); collapsed sections auto-expand while searching and restore when cleared× button inside the search field clears the query instantlyCmd Shift combos); combine as many as you like, together with searchCmd/Option on macOS, Ctrl/Alt/Win on Windows/Linux✕ button in the headerCmd P)| Key | Action |
|---|---|
Escape (search active) |
Clears the search input and restores pre-search collapse state |
Escape (search empty) |
Closes the modal |
Use the Export button in the modal toolbar to save the current cheatsheet in either format:
The plugin can optionally track how often you actually press each shortcut, so the cheatsheet can highlight what you use most and offer "most-used" sort modes. A few important points about what this does and doesn't do:
usage-data.json, inside this plugin's own folder in your vault (e.g. .obsidian/plugins/hotkeys-cheatsheet/usage-data.json). That file never leaves your machine.usage-data.json across devices. Counts are specific to how this machine is used — syncing it (via Obsidian Sync, git, Syncthing, etc.) will mix or overwrite counts from unrelated devices. If your vault is synced, exclude this file (e.g. add usage-data.json to .gitignore, or to your sync tool's ignore list).When enabled, usage shows up in the cheatsheet as small bar-glyph + count badges (e.g. ▅ 12) next to each shortcut and category heading, scaled relative to your most-used entries — and unlocks the By Most-Used Category / By Most-Used Shortcut sort modes.
Open Settings → Hotkeys Cheatsheet to configure:
| Setting | Default | Description |
|---|---|---|
| Show ribbon icon | On | Toggles whether the keyboard icon appears in the ribbon on startup. If disabled, the command palette entry still opens the cheatsheet. |
| Track shortcut usage | Off | Enables local-only shortcut usage tracking — see Shortcut usage tracking above for exactly what this does and doesn't do. |
| Reset usage statistics | — | Permanently clears all recorded shortcut usage counts (click twice to confirm). Only relevant when usage tracking is on. |
# Install dependencies
npm install
# Copy .env.example and set your vault plugin path
cp .env.example .env
# Production build → dist/main.js
npm run build
# Development build (sourcemaps, watch mode)
npm run dev
# Copy dist/ to your local vault plugin directory
npm run deploy
# Build + deploy in one step
npm run dev:deploy
# Remove dist/
npm run clean
src/
├── ts/
│ ├── main.ts Plugin entry point — ribbon icon, command, settings load/save
│ ├── settingsTab.ts Settings tab — ribbon toggle, usage tracking toggle + reset, about blurb
│ ├── types.ts Shared types (HotkeyBinding, CategoryGroup, SortMode, settings shape)
│ │
│ ├── modal/ The cheatsheet modal, split by concern
│ │ ├── cheatsheet.ts CheatsheetModal — lifecycle; wires state/toolbar/grid/export together
│ │ ├── state.ts CheatsheetState — search/filter/sort/collapse state + its invariants
│ │ ├── toolbar.ts Toolbar — export/filter/sort dropdowns, search box, collapse-all toggle
│ │ ├── grid.ts GridRenderer — category/flat rendering, entry rows, usage badges, search highlight
│ │ ├── export.ts Markdown generation, vault write w/ overwrite confirm, HTML download
│ │ └── htmlExportTemplate.ts Standalone HTML export template
│ │
│ ├── hotkeys/ Collecting, categorising, formatting, sorting, filtering hotkey data
│ │ ├── hotkeyCollector.ts Data layer — merges defaultKeys + customKeys, categorises, sorts
│ │ ├── categories.ts Curated prefix → category map and display order
│ │ ├── keyDisplay.ts OS-aware modifier/key display formatting
│ │ ├── sortHotkeys.ts The 5 sort modes (category/modifier/key/most-used-*)
│ │ └── filterHotkeys.ts Search + modifier-filter matching
│ │
│ ├── usage/ Shortcut usage tracking pipeline
│ │ ├── usageTracker.ts Capture keydown → signature, debounce persistence to usage-data.json
│ │ ├── usageResolver.ts Joins hotkey entries against captured usage counts
│ │ └── usageGlyph.ts Maps a usage count to one of 8 bar-glyph levels
│ │
│ └── i18n/
│ ├── i18n.ts Locale detection and t() helper
│ └── locales/
│ ├── en.json English strings
│ ├── fr.json French strings
│ └── es.json Spanish strings
└── css/
└── styles.css All plugin styles (Obsidian CSS vars, no hardcoded colours)
Obsidian exposes two internal maps on app.hotkeyManager:
app.hotkeyManager.defaultKeys // Record<commandId, Hotkey[]> — Obsidian built-in defaults
app.hotkeyManager.customKeys // Record<commandId, Hotkey[]> — user overrides
These are undocumented internal properties. A runtime guard checks for their existence and emits a console warning if they're missing (future-proofing against API changes).
Merge rule: if a command ID exists in customKeys, use those hotkeys (even [] — meaning the user cleared the default); otherwise fall back to defaultKeys.
Why not
getHotkeys(id)? It returns only user overrides, missing all built-in defaults (~41 hotkeys in a standard vault).
Commands are categorised using a hybrid strategy:
:) matches a curated map → use the mapped workflow category: in the ID → parse the display name for a "PluginName: …" pattern; fall back to "Other"Core category order: Editing → Navigation → Search → Files & Vault → Workspace → (plugin groups, alphabetical)
The plugin UI is available in English (default), French, and Spanish. Language is detected automatically from Obsidian's locale setting.
To add a new language:
src/ts/i18n/locales/en.json to src/ts/i18n/locales/<code>.json (e.g. de.json)en.jsonsrc/ts/i18n/i18n.ts:import de from "./locales/de.json";
const locales = { en, fr, es, de };
npm run buildBump the version — choose patch, minor, or major:
npm run release:prepare patch
Updates package.json and manifest.json, then commits both as "chore: bump version to X.Y.Z".
Make your code changes and commit them:
git add -A && git commit -m "feat: ..."
Publish — pushes the branch, creates a bare version tag (e.g. 1.1.6), and pushes the tag:
npm run release
The tag push triggers the GitHub Actions workflow, which builds and publishes the release.
Planned features and improvements for future releases: