Core Principle

fzf has two distinct window concepts with different resize semantics: the popup (set once at launch via --tmux "center,W,H", cannot be resized after) and the preview window (can be resized per-entry via the focus:transform bind emitting a change-preview-window(...) action). To make a picker feel “native” across heterogeneous entries, size the popup up-front to the widest entry and then re-size the preview on every focus change using a hidden per-row width field.

Why This Matters

Almost every intuitive “dynamic fzf window” idea hits the popup wall: the popup dimensions are fixed for the session. The focus:transform escape hatch is easy to miss because it’s listed under “transform” events rather than preview controls, and the common wrong turn is reaching for a nonexistent transform-preview-window action. Understanding the split saves hours of iteration. A second common miss is COLORTERM: fzf in a tmux popup inherits a reduced TERM and will silently downgrade truecolor content unless COLORTERM=truecolor is set in its environment.

Evidence/Examples

  • focus:transform:CMD: on every focus change, fzf runs CMD, which must print a fzf action string on stdout. fzf then executes that action. This is how you get per-entry preview behavior. Example: focus:transform:printf 'change-preview-window(right,%s,noinfo,follow)' {3} where {3} is a hidden width field on each row.
  • transform-preview-window does not exist. There is no such action. Only change-preview-window(...) exists; the dynamism comes from generating it via focus:transform.
  • --with-nth=N..: hides fields 1..N-1 from the visible list but keeps them accessible in binds via {1}, {2}, etc. This is how you attach per-row metadata (pane_id, socket, width, height) without showing it to the user.
  • COLORTERM=truecolor: fzf detects 24-bit color support from this env var. Tmux popups commonly inherit TERM=screen-256color, and fzf will strip truecolor bg sequences to 256-color approximations without COLORTERM=truecolor set. Prefix: COLORTERM=truecolor fzf ....
  • --ansi: required for fzf to pass through any ANSI escapes from preview output. Without it, fzf strips escape sequences and the preview is plain text.

Implications

  • Compute popup dimensions up-front from all entries’ dimensions (max(widths) + list_column + padding), then let focus:transform shrink the preview to match each entry. Don’t try to resize the popup.
  • Any fzf invocation that renders captured terminal content needs --ansi plus COLORTERM=truecolor in its env; otherwise truecolor silently degrades.
  • Store per-row metadata as leading hidden fields and expose them to binds via {N} placeholders. Don’t try to parse visible content to recover metadata.

Questions

  • Does fzf expose any event for “popup size changed” that would let you rebuild the list layout if the parent tmux window resizes mid-session?
  • Is there a way to set COLORTERM via fzf config rather than at invocation, so callers don’t have to remember the prefix?