Author: "Replace zsh's default completion selection menu with fzf!"
Go to file
Andrea Alberti 0fbd5753f9
feat: New style option to fzf-tab group headers: active-group-style (#553)
* Feat: support different styling for the group labels

* Fix: improved portability of code to macOS

* Refactor: use robust template file for ftb_preview_init

* refactor: retrieve active-group-style as array, simplify normalization

Keeps the type prefix consistent with the project history. It covers both changes: switching from -s to -a (which also changes the user-facing syntax to space-separated, consistent with all other multi-value zstyles), and replacing the 60-line anonymous function with a clean four-step variable breakdown.

---

```zsh
test_normalize() {
  local -a active_group_style=("$@")
  local -a _active_style_lower=(${(L)active_group_style})
  local -a _active_style_valid=(${(M)_active_style_lower:#(bold|underline|none)})
  local -a _active_style_sorted=(${(ou)_active_style_valid})
  local normalized=${${(j:,:)_active_style_sorted}:-none}
  echo "input=(${(j: :)active_group_style})  →  \"$normalized\""
}

test_normalize bold
test_normalize underline
test_normalize bold underline
test_normalize underline bold       # order should not matter
test_normalize BOLD UNDERLINE       # uppercase
test_normalize bold bold            # duplicates
test_normalize none
test_normalize italic               # unknown → none fallback
test_normalize bold italic          # mixed valid+invalid
test_normalize                      # empty → none fallback
```

input=(bold)  →  "bold"
input=(underline)  →  "underline"
input=(bold underline)  →  "bold,underline"
input=(underline bold)  →  "bold,underline"
input=(BOLD UNDERLINE)  →  "bold,underline"
input=(bold bold)  →  "bold"
input=(none)  →  "none"
input=(italic)  →  "none"
input=(bold italic)  →  "bold"
input=()  →  "none"

* fix: avoid code duplication in `initial_command` array and `reload_command` with 0 appended as the offset

Note: (z) splits the string using shell word-splitting rules, turning the string back into an array of tokens, then 0 is appended as the offset for the initial render.

Co-authored-by: Aloxaf <aloxafx@gmail.com>

* fix: restoring the (z) flag on $fzf_command. The original code used ${(z)fzf_command} which splits the command string into words. The PR changed it to just $fzf_command.

Co-authored-by: Aloxaf <aloxafx@gmail.com>

* refactor: changed `"${initial_command[@]}"` (POSIX-style expansion) to `$initial_command` (zsh-idiomatic expansion of an array)

Co-authored-by: Aloxaf <aloxafx@gmail.com>

* refactor: avoided anonymous function

Co-authored-by: Aloxaf <aloxafx@gmail.com>

* refactor: replaced echo for `print -r --` and removed trailing spaces

Co-authored-by: Aloxaf <aloxafx@gmail.com>

---------

Co-authored-by: Aloxaf <aloxafx@gmail.com>
2026-02-26 17:05:24 +08:00
.github ci: fix apt error 2025-09-18 10:02:25 +08:00
lib feat: New style option to fzf-tab group headers: active-group-style (#553) 2026-02-26 17:05:24 +08:00
modules fix: Fixed bug where color of symlinks was not suitably assigned because the case was not handled (#541) 2025-09-18 09:58:56 +08:00
test fix: prefix completion in quoted string (#448) 2024-06-12 13:52:43 +08:00
.gitignore Fix wd's completion 2019-12-26 04:53:52 +08:00
fzf-tab.plugin.zsh fix: compatibility with msys2 2021-11-30 14:59:14 +08:00
fzf-tab.zsh feat: support _approximate to correctly show correction options (#554) 2026-02-03 19:28:05 +08:00
LICENSE chore: update license year 2026-01-14 21:21:00 +08:00
README.md feat: Add use-fzf-default-opts (#479) 2024-10-11 09:38:14 +08:00

fzf-tab

CI GitHub license

Replace zsh's default completion selection menu with fzf!

asciicast

Table of Contents

Install

Important

  1. make sure fzf is installed
  2. fzf-tab needs to be loaded after compinit, but before plugins which will wrap widgets, such as zsh-autosuggestions or fast-syntax-highlighting
  3. Completions should be configured before compinit, as stated in the zsh-completions manual installation guide.

Manual

First, clone this repository.

git clone https://github.com/Aloxaf/fzf-tab ~/somewhere

Then add the following line to your ~/.zshrc.

autoload -U compinit; compinit
source ~/somewhere/fzf-tab.plugin.zsh

Antigen

antigen bundle Aloxaf/fzf-tab

Zinit

zinit light Aloxaf/fzf-tab

Oh-My-Zsh

Clone this repository to your custom directory and then add fzf-tab to your plugin list.

git clone https://github.com/Aloxaf/fzf-tab ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/fzf-tab

Prezto

Clone this repository to your contrib directory and then add fzf-tab to your module list in .zpreztorc.

git clone https://github.com/Aloxaf/fzf-tab $ZPREZTODIR/contrib/fzf-tab

Usage

Just press Tab as usual~

Available keybindings:

  • Ctrl+Space: select multiple results, can be configured by fzf-bindings tag

  • F1/F2: switch between groups, can be configured by switch-group tag

  • /: trigger continuous completion (useful when completing a deep path), can be configured by continuous-trigger tag

Available commands:

  • disable-fzf-tab: disable fzf-tab and fallback to compsys

  • enable-fzf-tab: enable fzf-tab

  • toggle-fzf-tab: toggle the state of fzf-tab. This is also a zle widget.

Configure

A common configuration is:

# disable sort when completing `git checkout`
zstyle ':completion:*:git-checkout:*' sort false
# set descriptions format to enable group support
# NOTE: don't use escape sequences (like '%F{red}%d%f') here, fzf-tab will ignore them
zstyle ':completion:*:descriptions' format '[%d]'
# set list-colors to enable filename colorizing
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
# force zsh not to show completion menu, which allows fzf-tab to capture the unambiguous prefix
zstyle ':completion:*' menu no
# preview directory's content with eza when completing cd
zstyle ':fzf-tab:complete:cd:*' fzf-preview 'eza -1 --color=always $realpath'
# custom fzf flags
# NOTE: fzf-tab does not follow FZF_DEFAULT_OPTS by default
zstyle ':fzf-tab:*' fzf-flags --color=fg:1,fg+:2 --bind=tab:accept
# To make fzf-tab follow FZF_DEFAULT_OPTS.
# NOTE: This may lead to unexpected behavior since some flags break this plugin. See Aloxaf/fzf-tab#455.
zstyle ':fzf-tab:*' use-fzf-default-opts yes
# switch group using `<` and `>`
zstyle ':fzf-tab:*' switch-group '<' '>'

Tmux

If you're using tmux >= 3.2, we provide a script ftb-tmux-popup to make full use of it's "popup" feature.

zstyle ':fzf-tab:*' fzf-command ftb-tmux-popup

BTW, you can also use this script outside the fzf-tab.

ls | ftb-tmux-popup

asciicast

For more information, please see Wiki#Configuration.

Binary module

By default, fzf-tab uses zsh-ls-colors to parse and apply ZLS_COLORS if you have set the list-colors tag.

However, it is a pure zsh script and is slow if you have too many files to colorize. fzf-tab is shipped with a binary module to speed up this process. You can build it with build-fzf-tab-module, then it will be enabled automatically.

Difference from other plugins

fzf-tab doesn't do "complete", it just shows you the results of the default completion system.

So it works EVERYWHERE (variables, function names, directory stack, in-word completion, etc.). And most of your configuration for default completion system is still valid.

Compatibility with other plugins

Some plugins may also bind "^I" to their custom widget, like fzf/shell/completion.zsh or ohmyzsh/lib/completion.zsh.

By default, fzf-tab will call the widget previously bound to "^I" to get the completion list. So there is no problem in most cases, unless fzf-tab is initialized before a plugin which doesn't handle the previous binding properly.

So if you find your fzf-tab doesn't work properly, please make sure it is the last plugin to bind "^I" (If you don't know what I mean, just put it to the end of your plugin list).

Related projects