Skip to content

Guide_Tabline

Shawon edited this page Mar 14, 2025 · 1 revision

πŸ“ Tabline: A beginners guide

Important

As tabline functions similar to statusline, I will be skipping over the basics. So, check that out first if you are new.

I recommend you try reading :h 'statusline' & :h 'tabline' first as it would help you understand how they work better.

πŸ‘€ Introduction

The tabline is the bar at the top of Neovim. It typically shows opened tabs.

So, we will keep it simple.

It also doesn't have anything similar to statusline items.

πŸ’₯ Creating a tabline module

Let's create a tabline.lua file with the following contents,

Note

Like the other bars, I will be assuming that you are using ~/.config/nvim/lua/tabline.lua

local tabline = {};

--- Helper function for applying
--- highlight groups.
---@param hl string
---@return string
local function set_hl (hl)
    if type(hl) ~= "string" then
        return "";
    elseif vim.fn.hlexists(hl) == 0 then
        return "";
    else
        return "%#" .. hl .. "#";
    end
end

--- Optional, configuration table.
--- Add this if you like tinkering.
tabline.config = {};

--- Function to create the tabline.
---@return string
tabline.render = function ()
    local _tabline = "";

    for _, component in ipairs(tabline.config) do
        local success, part_text = pcall(tabline[component.kind], component);

        if success then
            --- Only add text if a function doesn't fail.
            _tabline = _tabline .. part_text;
        end
    end

    return _tabline;
end

--- Optional, setup function.
tabline.setup = function (config)
    if type(config) == "table" then
        tabline.config = vim.tbl_deep_extend("force", tabline.config, config);
    end

    vim.o.tabline = "%!v:lua.require('tabline').render()";
end

return tabline;

🎁 Components

As the tabline doesn't provide items like the other bars, we have to create our own components that do what we need.

So, we will try making some simple components such as,

  • Tab list
  • Separator

🧩 Tabs

To keep things simple, we will just show the tab number and make it clickable.

Note

For listing other things, you can use nvim_list_bufs()(for buffers) or nvim_list_wins()(for windows).

The general idea is the same. To prevent overflowing outside the screen, you can limit the number of entries shown.

---@class tabline.tabs
---
--- Highlight group for current tab.
---@field active_hl? string
---
--- Highlight group for other tab(s).
---@field inactive_hl? string


--- Shows a list of tabs.
---@param config tabline.tabs
---@return string
tabline.tabs = function (config)
    local _o = "";
    ---@type integer[]
    local tabs = vim.api.nvim_list_tabpages();
    ---@type integer
    local current = vim.api.nvim_get_current_tabpage();

    for t, tab in ipairs(tabs) do
        if tab == current then
            --- Bug, Double clicking on the current tab
            --- will create a new tab. So, we don't
            --- add a click handler for this tab.
            _o = table.concat({
                _o,

                set_hl(config.active_hl),
                " ",
                tab,
                " "
            });
        else
            _o = table.concat({
                _o,

                "%" .. t .. "T",
                set_hl(config.inactive_hl),
                " ",
                tab,
                " ",
                "%X"
            });
        end

        if t ~= #tabs then
            _o = _o .. "%#Normal# ";
        end
    end

    return _o;
end

We can now add it to our config.

tabline.config = {
    {
        kind = "tabs",

        active_hl = "DiffAdd",
        inactive_hl = "Folded"
    },
};

🧩 Separator

We will use separators to center the tab list.

---@class tabline.separator
---
---@field hl? string

---@param config tabline.separator
tabline.separator = function (config)
    return set_hl(config.hl) .. "%=";
end

We can now finalize our config.

tabline.config = {
    { kind = "separator", hl = "Normal" },
    {
        kind = "tabs",

        active_hl = "DiffAdd",
        inactive_hl = "Folded"
    },
    { kind = "separator", hl = "Normal" },
};

πŸ”₯ More example

You can check more complex components, per-window configuration, click handling etc. in the source file.



Also available in Vimdoc, :h bars.nvim-tabline.

Clone this wiki locally