tmux's default pane navigation requires pressing your prefix keyThe key combo you press before a tmux command, e.g. Ctrl+b followed by an arrow key. If you switch panes dozens (or hundreds) of times a day, that means constantly moving your right hand away from its resting position to reach the arrow keys, then back again. It's a minor interruption each time, but these unnecessary hand movements add up and contribute to repetitive strain over time. My principle is that if you do something all the time, it should be as effortless as possible.
The simplest fix is to rebind navigation to hjkl (familiar from vim) in tmux directly:
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
This gets you on the home row. But pane switching is something you do constantly, and prefix + h/j/k/l is still two steps. First hit Ctrl+b and then h. We can do better: bind it to a single chord like Cmd+hjkl. For Mac users, Cmd is a natural choice (or Super on Linux). It's easy to reach and rarely conflicts with terminal applications.
There are some gotchas though. tmux itself can't see Cmd keypresses, so we can't just add tmux binds and call it. It's a limitation of how terminals work. Your terminal emulator has to intercept them and translate them into something tmux understands. This is where it gets hard to give universal advice, since every terminal handles custom keybinds differently. However, here's how to set it up in Alacritty and Ghostty.
The trick is to have Alacritty send your tmux prefix followed by the corresponding arrow key:
# \u0006 = C-f (my prefix). Replace with your prefix:
# C-b (default) = \u0002, C-a = \u0001, C-s = \u0013
[[keyboard.bindings]]
chars = "\u0006\u001B[D" # prefix + Left
key = "H"
mods = "Command"
[[keyboard.bindings]]
chars = "\u0006\u001B[B" # prefix + Down
key = "J"
mods = "Command"
[[keyboard.bindings]]
chars = "\u0006\u001B[A" # prefix + Up
key = "K"
mods = "Command"
[[keyboard.bindings]]
chars = "\u0006\u001B[C" # prefix + Right
key = "L"
mods = "Command"
In Ghostty, the same idea with different syntax:
# \x06 = C-f (my prefix). Replace with your prefix:
# C-b (default) = \x02, C-a = \x01, C-s = \x13
keybind = cmd+h=text:\x06\x1b[D
keybind = cmd+j=text:\x06\x1b[B
keybind = cmd+k=text:\x06\x1b[A
keybind = cmd+l=text:\x06\x1b[C
In both cases, \u0006 / \x06 is the ASCII code for
Ctrl+F (my prefix key), and \u001B[D / \x1b[D etc. are
the ANSI escape sequences for arrow keys. So pressing
Cmd+h sends C-f ←, which tmux
interprets as "switch to the pane on the left." Adjust the prefix character if
yours is different. For example, C-b (the default) would be \u0002
/ \x02.
#Hide Window: A small macOS annoyance
It doesn't end here, sadly. On Mac, Cmd + h is a reserved global hotkey for hiding the currently active window. By default, macOS will intercept the mapping before it reaches your terminal, performing the Hide Window action. Fortunately there's a way around this.
Go to System Settings → Keyboard → Keyboard Shortcuts… → App Shortcuts, and for your terminal app of choice, add a new custom keyboard shortcut to override the menu item name, for example "Hide alacritty". Just map it to any random key combination you're never going to use. At least I never hide my terminal window.
There you go. Enjoy the bliss of never leaving the home row. At least when navigating your tmux panes.