understanding the per-mode bind and unbind syntax in config.kdl, clear-defaults and strategies for building keybindings from scratch, and how to handle conflicts with the shell and editors.

Welcome back to the Learn Zellij series! You've made it through eight episodes: prerequisites and setup, history, client-server architecture, session and pane lifecycle, keybinding and the mode system, advanced pane management, scrollback and search, floating panes, and in episode 8 you met the complete config.kdl structure. Now it's time to make Zellij truly yours: episode 9 thoroughly dissects custom keybindings and the conflicts that come with them.
There are six things you'll master in this episode: (1) the per-mode bind and unbind syntax inside the keybinds block, (2) clear-defaults for building keybindings from scratch, (3) multi-action keybinds and multiple modifiers, (4) stacked resize, (5) how to diagnose and resolve conflicts with your shell and editor, and (6) safe, sustainable remap strategies. All the examples below reference Zellij 0.44.x, so make sure your version isn't too far behind.
Why does this episode matter? Zellij's default keybindings are designed for the majority of users, but majority doesn't mean you. Every developer has a favorite editor, habits, and deeply rooted workflows. When Zellij shortcuts clash with vim, neovim, or shell shortcuts, what happens isn't the end of the world — it's a matter of collaboration between two applications both hungry for the keyboard. Understanding how Zellij binds, unbinds, and overrides keybindings is the skill that separates a casual user from a power user. Let's begin.
All keybindings live inside the keybinds block in config.kdl. Unlike tmux's prefix keys: Zellij uses modes. Every mode has its own keybinding set, and its hints always appear at the bottom of the screen. Here are the main modes you already know from episode 4:
| Mode | Prefix | Function |
|---|---|---|
| Normal | - | Base mode; unbound keys are passed through to the shell |
| Pane | Ctrl+p | Pane navigation and management |
| Tab | Ctrl+t | Tab navigation and management |
| Resize | Ctrl+n | Resize panes |
| Move | Ctrl+h | Move pane positions |
| Scroll | Ctrl+s | Scroll and search the scrollback |
| Session | Ctrl+o | Sessions, detach, plugin manager |
| Locked | Ctrl+g | Lock all input |
| Tmux | Ctrl+b | tmux keybinding emulation |
The basic syntax is simple: a mode node inside keybinds, then bind instructions with one or more keys, followed by a block containing one or more actions. KDL uses double-quoted strings, and actions end with a semicolon.
keybinds {
normal {
bind "Ctrl p" { SwitchToMode "Pane"; }
}
pane {
bind "h" "Left" { MoveFocus "Left"; }
bind "n" { NewPane; SwitchToMode "Normal"; }
}
shared_except "locked" {
bind "Alt n" { NewPane; }
}
}Note three things in the example above. First, one bind can hold many keys: bind "h" "Left" makes both the h key and the left arrow key perform the same action. Second, one key can trigger many actions: bind "n" { NewPane; SwitchToMode "Normal"; } creates a new pane then immediately returns to Normal mode — the most common pattern in Zellij keybindings. Third, the shared_except "locked" block defines keybindings that apply in all modes except the ones listed, so a shortcut like Alt n works wherever you are.
Tip
If you don't want to memorize all the action names, run zellij setup --dump-config to copy the default config to a file, then read the keybinds block there as a complete dictionary: actions like MoveFocus, NewPane, Resize, GoToTab, EditScrollback, up to ToggleFloatingPanes are all listed with their default keys. Zellij's configuration is also reloaded live, so every change is felt instantly without restarting a session.
Sometimes overriding per-key isn't enough. You may want to start from a blank page and define everything yourself. Zellij provides two tools: unbind to remove specific keys, and the clear-defaults=true attribute to wipe all defaults in a single node.
keybinds {
unbind "Ctrl g"
normal {
unbind "Ctrl p" "Ctrl t"
}
pane clear-defaults=true {
bind "h" "Left" { MoveFocus "Left"; }
bind "l" "Right" { MoveFocus "Right"; }
bind "j" "Down" { MoveFocus "Down"; }
}
}There's one thing to get straight from the start: there's no unbind-all keyword in Zellij. To remove all defaults at once, use keybinds clear-defaults=true on the keybinds node itself. The difference from putting the same attribute on a single mode is important:
| Method | Scope | Effect |
|---|---|---|
unbind "Ctrl g" under keybinds | All modes | Removes one key across all modes |
unbind "Ctrl p" "Ctrl t" inside a mode | One mode | Removes several keys in that mode |
pane clear-defaults=true | One mode | Clears all of that mode's defaults |
keybinds clear-defaults=true | Global | Clears all defaults of all modes |
When using clear-defaults=true globally, you're responsible for redefining the bridges between modes — for example the way into Pane mode (Ctrl p), the way back to Normal mode (Esc/Enter), and the Ctrl g key for Locked. Otherwise the UI will feel "locked" because there's no path to switch modes. This isn't a bug; it's a consequence of removing the defaults.
Important
clear-defaults=true also removes the shared_except bindings that are the backbone of inter-mode navigation, including Esc/Enter to return to Normal and Ctrl q to quit. If you use it globally, make sure the following minimum example exists in the config: bind Ctrl p to SwitchToMode "Pane", bind Ctrl g to SwitchToMode "Locked", and bind Esc/Enter to SwitchToMode "Normal" in the appropriate shared_except block.
Zellij has long supported many actions in a single keybind — for example bind "n" { NewPane; SwitchToMode "Normal"; } — but since version 0.43 this support was significantly expanded. First, the NewPane action now accepts a "Stacked" argument so a single keybind can directly open a stacked pane on top of the focused pane. This is exactly what drives the new default Ctrl p + s.
keybinds {
pane {
bind "s" { NewPane "Stacked"; SwitchToMode "Normal"; }
bind "Alt r" "Ctrl Alt r" { NewPane "Right"; SwitchToMode "Normal"; }
}
}Second, 0.43 added multiple modifier support. Previously you were limited to one modifier (for example Alt r); now combinations like Ctrl Alt r or even Ctrl Shift Home can be bound. This capability runs on top of the kitty keyboard protocol: Zellij asks the host terminal to send a richer key encoding, so keys that previously couldn't be distinguished can now be separated. If your terminal doesn't support this protocol, Zellij still works normally because the protocol is backward-compatible.
One small caveat: the official docs state that actions in a single keybind have no guaranteed execution order. For practical purposes, sequential actions on the same line are almost always run in order, but you shouldn't build logic that depends on that guarantee. If you truly need strict ordering, run via Run or a CLI action — a topic we'll dig into in episode 13.
Tip
Multiple modifiers are a powerful weapon against conflicts: instead of fighting over Ctrl and Alt, you can move some shortcuts to Ctrl Alt combinations that almost no other application uses. Pick one pattern — for example all pane actions use Ctrl Alt and all navigation uses Alt — then apply it consistently.
A very influential feature for the resize experience comes from version 0.42: stacked resize. Previously, resizing a pane with Alt + +/- only shifted the boundary between panes and stopped when it collided. From 0.42, this algorithm was replaced: when you press Alt +, Zellij tries to enlarge the pane to 30% of the screen; if that's impossible in any direction, the pane will stack with its neighbor — the other pane's title stays visible as a small tab beneath it, so you can navigate there with the keyboard or mouse. Pressing Alt - pops the pane out of the stack, and the previous size is remembered like an undo chain.
stacked_resize falseThis behavior is on by default and can be turned off with stacked_resize false at the root of config.kdl. The combination of stacked resize (0.42) and stacked pane keybinding (0.43) lets Zellij handle dense screens gracefully: a squeezed pane automatically becomes a stack, and new panes opened above a stacked pane join the stack. For workflows with many small panes — monitoring, logs, split editors — this feature feels like something you never knew you desperately needed until you try it.
This is the heart of the episode. Conflicts happen when a key Zellij uses is also consumed by an application inside a pane. Classic example: vim/neovim users use Ctrl+o to jump to the jumplist, but Ctrl+o is Zellij's Session mode prefix. Another example: Ctrl+w to close a tab in an editor, while some Zellij setups use it for something else. Before you panic, understand Zellij's key forwarding policy that changed in 0.41: keys that are unbound will be forwarded verbatim to the terminal as long as the active mode is locked or default_mode (by default normal). In other modes, keys only take effect if they're actually bound. That means in Normal mode, Ctrl+o in vim isn't actually eaten by Zellij — the problem arises when you switch to another mode, or when the preset policy doesn't match your habits.
Zellij offers several layers of solutions for this conflict:
| Strategy | How | When to Use |
|---|---|---|
| Non-colliding preset | Ctrl+o then c, choose Unlock-First | Conflicts spread across many applications |
| Change leader key | Ctrl+o then c, change the leader modifier | Only one/three keys are problematic |
unbind in config | Remove a specific key | Conflict on one specific key |
| Remap | Move the action to another combination | You still want to keep the Zellij action |
Write action | Send raw keys to the pane | You want the key to reach the application |
The Unlock-First (non-colliding) preset introduced in 0.41 is a comprehensive solution: Zellij starts in a locked state, and you press Ctrl+g first to "unlock" the interface before accessing modes. Because all modes are accessed after unlocking, there are almost no collisions with applications inside panes. For those wanting manual control, the two remap patterns below are often the choice of vim users:
keybinds {
unbind "Ctrl o"
shared_except "session" "locked" {
bind "Ctrl Space" { SwitchToMode "Session"; }
}
}Option one frees Ctrl+o entirely for vim, with the consequence that the way back from Session mode shifts to Esc/Enter. Option two moves the leader to Alt+o, which is safer because Alt is rarely used by editors. Pick one, then adjust to your editor. For the AltGr case on non-US keyboards that causes problems on Windows, turn off kitty keyboard protocol support with support_kitty_keyboard_protocol false in the config — a solution proven to help many users.
Don't forget the escape hatches: Locked mode (Ctrl+g) and the Write action which sends raw keys to the pane. When you're in a specific mode and want a combination forwarded as-is to the application, Write — for example Write 27 111 to send Alt+o — is an explicit, predictable way. This pattern is very useful for nested Zellij, which we'll discuss in more depth in episode 21.
Closing this episode, let's summarize the remap strategy you should apply so you don't end up with a chaotic config. First principle: start from the defaults, then edit what you need. Zellij's defaults have been tested by thousands of users; building from scratch with clear-defaults=true only makes sense if you have a strong reason and are ready to maintain it. Second principle: don't change a mode prefix without counting the effects — prefixes like Ctrl p are also used as the way back from Pane mode, so changing it means changing both directions at once.
Third principle: stay consistent with modifiers. If you decide quick actions use Alt, don't mix in Ctrl Alt halfway through. The power of multiple modifiers is born from order. Fourth principle: document via dotfiles. Keep ~/.config/zellij/ in a dotfiles repo as we'll discuss in episode 27, so every keybinding change is recorded in git history and easily synced to other machines. Finally, test in real sessions. The most dangerous conflicts aren't the ones visible in the config, but the ones you only feel after thirty minutes of work — so get used to noting keys that feel "swallowed" by Zellij and resolve them one by one.
clear-defaults=true without redefining mode switches. The UI feels locked because there's no way into Pane/Tab modes, no Esc/Enter to return to Normal, and no Ctrl q to quit. Fix: always include the minimum bindings for mode switching when using clear-defaults=true.shared_except. The conflict still remains in other modes. Fix: check the shared_except block and unbind at the keybinds level if you want to remove a key across all modes.unbind-all keyword that doesn't exist. To remove all defaults, use the clear-defaults=true attribute on the keybinds node; no such keyword exists in Zellij.NewPane in Normal mode — the action will never trigger because Normal mode forwards keys to the shell. Fix: learn the mode table, and place actions in the mode that actually owns them.bind aren't guaranteed to be in order. If the flow must be precise (open pane, rename, etc.), use a CLI action or Run, covered in episode 13.Warning
Don't copy keybinding config from tutorials without understanding the actions. Zellij doesn't validate whether the combination you write makes sense — a mistyped config only stays silent, and you only notice when the expected shortcut doesn't work. A small habit that saves you: after editing config.kdl, immediately press the combination and check the hints in the status bar.
In this episode 9 you've mastered the anatomy of Zellij keybindings: per-mode bind and unbind, the shared_except block for cross-mode shortcuts, clear-defaults=true as the replacement for the nonexistent "unbind-all", multi-action keybinds with multiple modifiers from 0.43, stacked resize from 0.42, and layered strategies for resolving conflicts with the shell and editor — from the non-colliding preset, to changing the leader key, to manual remapping.
Key takeaways:
clear-defaults=true removes defaults; you must redefine the inter-mode bridges.Ctrl Alt) are the modern solution to key conflicts.unbind, or remap.Now you can press keys the way you want. In episode 10 next, we'll arrange the room — not the keys: KDL layouts and project workspaces, where you define panes, tabs, sizes, cwd, environments, and commands in a single layout file that can be run with zellij -l. See you in episode 10, and happy building keybindings that feel like your own!