Leveraging modern tmux 3.3 to 3.7 features: display-popup for floating terminals, display-menu for custom menus, floating panes, pane scrollbars, hyperlinks, and copy mode line numbers plus a development menu case study.

In episode 21 we covered nested tmux & advanced input handling — sending prefixes between layers and optimizing mouse, extended keys, focus events, clipboard, and end-to-end colors. This time we level up the interface: from merely splitting the screen to building interactive UIs on top of tmux — popups, menus, and the latest stable features that change how tmux feels.
Why does this topic matter? The modern terminal isn't a "monochrome green screen" anymore. As an engineer, you repeat the same actions constantly: switching sessions, checking git status, viewing logs, running tests. Each action needs several keypresses and context switches. display-popup and display-menu turn those actions into a single call: press one key, pick from a menu, done. In production, reducing friction like this means reducing errors — the fewer steps, the fewer things that can go wrong. This episode refers to tmux 3.7b as the latest stable version.
display-popup (since tmux 3.0) opens a small terminal floating in the middle of the screen — like a popup window, but still inside tmux. Its size and position can be set with -w, -h, -x, and -y:
tmux display-popup -E -w 80% -h 80% "lazygit"-w and -h accept absolute numbers or percentages; -x and -y set the relative position. Without arguments, the popup uses half the terminal size in the center. The -E flag makes the popup run a command and close when it finishes; without -E, the popup opens an interactive shell that persists until you close it. -d sets the starting directory, e.g. -d ~/project.
Since tmux 3.3, popups can have a title and a customizable border — and now look like real windows, not just boxes:
tmux display-popup -E -w 70% -h 70% -T "Lazygit" -b rounded "lazygit"
tmux display-popup -B -h 40% -E "htop"-T "Title" displays a title on the top border (tmux 3.3+).-b rounded sets the border line style; -B removes the border entirely (for tools that already have their own border).-e VAR=value injects an environment for the popup; -s and -S set the popup's and its border's styles.-k (tmux 3.6+) lets the popup be closed with any key after the command finishes, instead of only waiting for Enter.Note
A popup is an overlay: while open, input goes to the popup, while the pane behind it keeps running and you can see its output. This distinguishes it from floating panes, which we'll discuss shortly — a popup is modal for input, a floating pane is not.
display-menu (since tmux 3.0) builds a popup menu from a series of name, key, and command arguments — repeated for each item:
bind M display-menu -T "Action" \
"New window" n "new-window" \
"Split right" v "split-window -h" \
"" \
"Detach" d "detach-client"name becomes a separator (both key and command are omitted).- makes the item disabled (dimmed, unselectable).key is the shortcut to pick the item from the keyboard; leave it empty when not needed.-T "Title" shows the menu title; -C sets the item selected when the menu opens.The menu waits for keyboard input: select with Up/Down + Enter, q to close. The -O option prevents the menu from closing automatically when the mouse button is released without selecting, and -M enables full mouse handling — both useful when the menu is triggered from a mouse binding.
A menu that can't be summoned is a useless menu. Bind it to a key on the prefix, or to a key without a prefix (-n) for very frequent actions:
bind M display-menu -T "Quick" \
"List sessions" s "choose-tree -s" \
"Paste buffer" p "choose-buffer"This pattern turns three abstract keypresses into one visible menu. The more often an action is performed, the more it deserves to be a menu item — not the other way around.
A floating pane is the newest feature of tmux 3.7: a pane floating above the layout like a popup, but not modal — it behaves like a regular pane and supports the same escape sequences. Create one with the default binding Prefix + *, then drag and resize with the mouse. The pane_floating_flag format tells you whether a pane is floating.
tmux display-message -p '#{pane_floating_flag}'Caution
Floating panes are a young feature. In early releases, moving and resizing is mouse-only, and some operations like resize-pane, swapping panes, or restoring custom layouts don't support floating panes yet. Suited for "temporary" panes that are easy to discard — treat this feature as a bonus, not the foundation of your work layout.
Since tmux 3.6, every pane can show a scrollbar beside it — a scrollback position indicator that previously could only be sensed vaguely:
set -g pane-scrollbars on
set -g pane-scrollbars-position right
set -g pane-scrollbars-style fg=#555pane-scrollbars-position chooses left or right; pane-scrollbars-style sets its color. The scrollbar appears when entering copy mode and really helps map how deep the scrollback goes — especially in panes with long output like logs.
tmux supports OSC 8 hyperlinks (since 3.4): URLs printed by applications inside a pane become clickable links in terminal emulators that support it. In copy mode (tmux 3.5+), hyperlinks are displayed and can be copied with the copy_cursor_hyperlink format — e.g. copying the URL the cursor is pointing at, instead of copying a line that may be truncated.
tmux 3.7 adds line numbers in copy mode via copy-mode-line-numbers:
set -g copy-mode-line-numbers relative| Value | Meaning |
|---|---|
off | No line numbers |
default | Normal tmux numbering (top visible line = 0) |
absolute | First line in history = 1 |
relative | Numbers relative to the cursor |
hybrid | Cursor line absolute, others relative |
Along with that, the copy-line and copy-line-and-cancel commands make per-line selection explicit — drag with the mouse to select lines, or run the command to copy the line the cursor is on. This solves the "copy that specific log line" job that previously required manual selection.
Let's assemble everything into one real workflow. Imagine you're working on a Go project: running tests, checking git, and switching sessions are daily activities. We'll build a project menu callable with Prefix + P, plus popups for tools that need a big screen.
A static menu can't show ever-changing sessions. The solution: build the session list from tmux list-sessions, then construct the menu arguments dynamically:
#!/usr/bin/env bash
mapfile -t sessions < <(tmux list-sessions -F '#S')
menu=()
for s in "${sessions[@]}"; do
menu+=("$s" "" "switch-client -t $s")
done
tmux display-menu -T "Switch session" "${menu[@]}"Bind that script to a key, and the menu shows all existing sessions — items are added and removed following the server's real condition. This is the dynamic menu pattern: data from the system, display from tmux.
bind S run-shell ~/.config/tmux/scripts/session-menu.shFor actions that need to see a lot of output — git log, status, or heavy processes — a popup fits better than a menu. display-popup runs the command, shows the result in the middle of the screen, and closes itself:
bind L display-popup -E -w 80% -h 80% -T "Git log" \
"git log --oneline --graph --decorate -20"bind P display-menu -T "Project" \
"Run tests" t "display-popup -E -T 'Test' 'pytest -q'" \
"Git status" g "display-popup -E -T 'Git' 'git status -sb'" \
"Git log" l "display-popup -E -T 'Log' 'git log --oneline -20'" \
"" \
"Detach" d detach-clientNote the division of roles: display-menu for quick choices (what you want to do), display-popup for temporary workspace (tools that need a screen). Both reduce steps — and every step removed is one less chance to mis-press a key.
list-sessions/list-buffers via run-shell, not items hardcoded in the config.-E on display-popup. Without -E, the popup opens an interactive shell and doesn't close after the command finishes — the result is a popup that "sticks" and must be closed manually.display-popup/display-menu need tmux 3.0+, pane-scrollbars needs 3.6, floating panes and line numbers need 3.7. Check tmux -V before using features on a production server.This episode opened a new dimension of the tmux interface. You understand display-popup as a floating terminal with configurable geometry, title, and border; display-menu as a custom menu based on name, key, and command; and the newest stable features from 3.6 to 3.7 — floating panes, pane scrollbars, OSC 8 hyperlinks, and line numbers in copy mode. The development menu case study showed how to assemble all of it into a workflow people actually use: dynamic session switching, git popups, and a project menu in one config.
Key points to take away:
display-popup for temporary workspace; display-menu for quick choices.list-sessions), not hardcoded.In episode 23 we'll cover troubleshooting & debugging — when tmux doesn't behave as expected: reading server logs, diagnosing status bar and color issues, tracing keybinding conflicts, and reproducing problems with a minimal config. See you in episode 23!