Which-key shows available key continuations in a popup after you press a partial key sequence. Similar to Neovim’s which-key.nvim, it helps you discover and remember keybindings without consulting documentation.
Modes
Configure via Settings → Vim Motions → Which-key hints, vim.opt.whichkey = "mode" in Lua, or set whichkey=<mode> in vimrc.
Mode
Behavior
off
No popup (default)
leader
Popup appears only after pressing the leader key
all
Popup appears after any partial key sequence
This setting controls which-key in all contexts: the main editor, non-editor views, and embedded editors. In non-editor views (graph, canvas, PDF, reading mode), the which-key popup shows global binding completions — for example, pressing <C-w> shows available window commands (h, j, k, l, v, s, etc.).
In all mode, pressing d shows available motions and text objects, g shows g-prefixed commands, z shows fold commands, [ and ] show bracket motions, etc.
Embedded editors
Which-key works in table cell editors (embedded table widget mode) and textarea vim overlays (experimental vim-in-textareas feature). The popup renders in the parent note’s viewport using the same position and styling as the main editor — visually seamless.
All user keymaps (vimrc, Lua) are available in embedded editors since the vim keymap is shared globally. Leader key drill-down, group labels, command labels, and icons all work identically.
In embedded editors, the popup show delay is bypassed — partial chords show completions immediately for fast, focused editing sessions.
Bundled vim mode only
Which-key in embedded editors requires the bundled vim fork (Obsidian’s built-in vim mode disabled). Embedded editors do not receive vim in built-in vim mode.
Popup delay
Configure via Settings → Vim Motions → Which-key popup delay, vim.opt.whichkeydelay = <ms> in Lua, or set whichkeydelay=<ms> (alias wkd) in vimrc.
The delay controls how long to wait (in milliseconds) before the which-key popup first appears after a partial key sequence. The default is 500 ms. Set to 0 for instant display.
Once the popup is visible, subsequent keystrokes update it instantly — the delay only applies to the initial appearance. Single-key commands that resolve immediately (like j, k) never trigger the popup regardless of delay.
vim.opt.whichkeydelay = 300 -- show after 300ms
" Or via vimrc:set whichkeydelay=300set wkd=0
Grouping
Configure via Settings → Vim Motions → Which-key leader grouping, vim.opt.whichkeygrouping = "mode" in Lua, or set whichkeygrouping=<mode> in vimrc.
Mode
Behavior
grouped
Collapse bindings by prefix (default). Pressing <leader> shows t → Table (+11) instead of listing all table commands. Press t to drill into the group.
flat
Show all bindings in a flat list without grouping
Multi-key prefixes are grouped correctly. EasyMotion commands (<leader><leader>f, <leader><leader>w, etc.) appear as a single “EasyMotion” group after the first <leader> press. Pressing the second <leader> drills into the group to show individual EasyMotion commands.
Sort order
Configure via Settings → Vim Motions → Which-key hints → Which-key sort order, vim.opt.whichkeysort = "order" in Lua, or set whichkeysort=<order> (alias wks) in vimrc.
Mode
Behavior
which-key
Matches which-key.nvim defaults (default). Individual keys first, groups last. Alphanumeric keys before special keys (<…>). Natural alphabetical tiebreaker.
groups-first
Groups appear before individual keys. Both categories sorted alphabetically.
vim.opt.whichkeysort = "groups-first"
" Or via vimrc:set whichkeysort=groups-firstset wks=which-key
Icons
Configure via Settings → Vim Motions → Which-key hints → Which-key icons, vim.opt.whichkeyicons = true in Lua, or set whichkeyicons in vimrc.
When enabled, icons appear next to entries in the which-key popup. Built-in groups (Table, EasyMotion, Harpoon, etc.) show default icons automatically.
Assigning icons to groups
Icons use Lucide icon names from Obsidian’s built-in icon library.
vim.obsidian.whichkey.set_group("<leader>t", "Table", { icon = "table", color = "blue" })vim.obsidian.whichkey.set_group("<leader>g", "Git", { icon = "git-branch", color = "orange" })
" Or via vimrc:whichkeygroup <leader>t Table icon=table color=bluewhichkeygroup <leader>g Git icon=git-branch color=orange
" Or via vimrc:whichkeygroup <leader>t Tablewhichkeygroup <leader>g Gitwhichkeygroup <leader>f Find
Group labels can also be configured in Settings → Vim Motions → Which-key group labels. Use the leader character + prefix for leader groups (e.g., \t for table if leader is \), or a raw prefix for non-leader groups.
Built-in features register default group labels. Your entries override the defaults for the same prefix.
Command labels
Describe individual bindings shown in the which-key popup.
In Lua, use the desc option in vim.keymap.set:
vim.keymap.set("n", "<leader>w", ":w<CR>", { desc = "Save file" })-- The `desc` option automatically appears in which-key
In vimrc:
whichkeylabel <leader>w Save filewhichkeylabel <leader>q Close tabwhichkeylabel gd Go to definitionwhichkeylabel gO Document outline
Command labels can also be configured in Settings → Vim Motions → Which-key command labels. Labels set in vimrc appear as read-only rows in the settings UI.
Batch labels (add())
Define multiple group and command labels at once with vim.obsidian.whichkey.add(), similar to Neovim’s which-key.nvimwk.add() syntax:
Assign vim.obsidian.whichkey to a local for a more familiar feel:
local wk = vim.obsidian.whichkeywk.add({ { "<leader>f", group = "Find" }, { "<leader>g", group = "Git" }, { "<leader>t", group = "Table" },})
Reserved fields
The mode field is accepted but currently ignored. It is reserved for future mode-scoped label support.
Merge behavior
Group and command labels from Lua, vimrc, and Settings are merged. If the same key appears in multiple sources, the hierarchy is: Lua > vimrc > Settings.
Tips
Start with leader-only mode
If you’re new to which-key, start with vim.opt.whichkey = "leader" to see the popup only for leader bindings. Switch to all once you’re comfortable.
Organize with groups
Use the desc option in Lua or whichkeygroup in vimrc to name your custom leader binding groups. The grouped display is more readable when you have many bindings.
Global (non-editor) labels
Label global bindings separately from editor bindings:
The desc option in vim.obsidian.keymap.set automatically creates a global which-key label. Use vim.obsidian.whichkey.set_group/set_label with { context = "global" } for additional labels.
" Or via vimrc:gwhichkeygroup <leader> +leader bindingsgwhichkeylabel <leader>f Open filegwhichkeylabel <leader>e Reveal in explorer
These labels appear in the non-editor which-key overlay. They are independent from editor which-key labels — the same key prefix can have different labels in each context.
Each binding’s desc is registered as a which-key command label for the resolved leader key sequence (e.g., <Space>e → “Reveal in explorer”). No separate whichkeylabel or vim.obsidian.whichkey.set_label call is needed.
Automatic labels from vim.keymap.set
Leader-prefixed keymaps registered via vim.keymap.set with a desc option automatically appear in the which-key overlay:
vim.keymap.set("n", "<leader>ff", function() vim.cmd("obcommand switcher:open")end, { desc = "Find file" })-- "ff → Find file" appears in which-key when leader is pressed
Group labels set via vim.obsidian.whichkey.add() work with both vim.keymap.set and vim.obsidian.leader.add bindings:
local wk = vim.obsidian.whichkeywk.add({ { "<leader>f", group = "Find" },})vim.keymap.set("n", "<leader>ff", function() vim.cmd("obcommand switcher:open")end, { desc = "Find file" })vim.keymap.set("n", "<leader>fg", function() vim.cmd("obcommand global-search:open")end, { desc = "Grep" })-- Pressing leader shows: f → Find (+2)-- Pressing leader then f shows: f → Find file, g → Grep
Automatic descriptions for obcommand mappings
When a key is mapped to :obcommand <id><CR> or :ob <id><CR> without a desc option, the which-key popup automatically resolves and displays Obsidian’s native command name instead of the raw ex command string:
If the command ID doesn’t exist (e.g., from an uninstalled plugin), the description falls back to the raw command string. Resolved names are automatically localized — Obsidian’s built-in commands already have translated names, so descriptions match your Obsidian language setting.
When the Oil file explorer is open and Obsidian’s built-in vim mode is disabled (fork mode), the which-key popup shows Oil-specific keybindings (g., gs, gf, g?) with descriptive labels alongside standard bindings. Oil bindings appear as individual completions when typing partial keys — they are dynamically mapped on OilEnter and removed on OilLeave, so they only appear in which-key while an Oil view is active. Press g? in Oil (or :oilhelp) to open a help modal listing all Oil keybindings.
Fork mode only
Oil which-key integration requires fork mode (built-in vim disabled). With built-in vim enabled, the embedded Oil editor does not have access to the fork’s CM adapter.
Instant overlay in Oil
In “All partial keys” mode, the which-key popup delay is automatically bypassed when an Oil view is active. The overlay appears immediately on partial keys, allowing multi-key bindings (g?, g., gs, gf) to complete without interference. This matches the delay=0 behavior and preserves operator-pending hints (d, c, y) in Oil.