Open-source project
xiyaowong/transparent.nvim avatar
xiyaowong/transparent.nvim

transparent.nvim clears Neovim highlight backgrounds and keeps them cleared

Remove all background colors to make nvim transparent

1,187 stars25 forksLuaMIT

At a glance

What is it?
transparent.nvim is a small Lua plugin that removes background colours from Neovim's highlight groups, with configuration for extra, excluded and dynamically computed groups, prefix clearing for plugins that define highlights at runtime, and enable, disable and toggle commands. It is MIT licensed, and the last push was on 2026-10-11.
Who is it for?
transparent.nvim suits a Neovim user on a terminal with a translucent or image background who wants the editor to stop painting panels over it, and it is the wrong tool if you want the whole colour scheme to change, because it only clears backgrounds and leaves foregrounds alone. Before installing, read the note about not lazy loading it, since the clearing logic only runs if the plugin is loaded early enough.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 12 days ago.
What is it written in?
Mainly Lua, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem is a colour scheme that paints over your background

transparent.nvim removes all background colors to make nvim transparent, and that is the entire premise. The plugin is a handful of Lua files, a LICENSE and a stylua.toml, with lua/ holding the module and plugin/ holding the command definitions.

The problem it solves is specific and common. A Neovim colour scheme sets a background colour on the Normal highlight group and on every other group that draws a panel, so a terminal configured with a translucent background or an image ends up with an opaque rectangle in the middle of it. The fix is to set the background of those groups to none, which is what this plugin does.

What it does not do is change the foreground colours. The plugin is not a theme and it is not a colour scheme manager. It clears the background of groups and leaves everything else about the appearance alone, which is why it composes with whatever colour scheme you already use rather than replacing it.

The README also notes an acknowledgement to vim-transparent, which is the earlier project this one takes its idea from.

The plugin is MIT licensed, has no GitHub releases, and the last push was on 2026-10-11, so it is a small project that is still being worked on rather than a packaged, versioned component.

The setup block is the whole configuration surface

Normally, you don't need to call setup, and the README says so explicitly, pointing at two better ways to configure. The setup function is still there with all the options, and it is worth reading to know what the plugin is capable of:

lua
-- Optional, you don't have to run setup.
require("transparent").setup({
  -- table|function: default groups
  groups = {
    'Normal', 'NormalNC', 'Comment', 'Constant', 'Special', 'Identifier',
    'Statement', 'PreProc', 'Type', 'Underlined', 'Todo', 'String', 'Function',
    'Conditional', 'Repeat', 'Operator', 'Structure', 'LineNr', 'NonText',
    'SignColumn', 'CursorLine', 'CursorLineNr', 'StatusLine', 'StatusLineNC',
    'EndOfBuffer',
  },
  -- table|function: additional groups that should be cleared
  extra_groups = {},
  -- table|function: groups you don't want to clear
  exclude_groups = {},
  -- function: code to be executed after highlight groups are cleared
  -- Also the user event "TransparentClear" will be triggered
  on_clear = function() end,
})

The default list is the interesting part. It is not every group in a standard highlight table. It is a curated set of the ones that actually carry a background in practice, including Normal and NormalNC, the syntax groups, LineNr, SignColumn, CursorLine, CursorLineNr, the two StatusLine groups and EndOfBuffer.

Note that CursorLine is in the default list. That means the line highlight is cleared too, which is a choice some people will want and some will not, and it is the kind of thing exclude_groups exists for.

The on_clear callback runs after the groups are cleared, and the same operation also triggers a user event named TransparentClear, so other parts of your configuration can react to the plugin having run. The two mechanisms cover the same event from Lua and from Vimscript, which matters for a plugin that other plugins need to coordinate with.

Dynamic groups solve the problem of highlights that do not exist yet

The three list options, groups, extra_groups and exclude_groups, all accept a function as well as a table, and that is the feature that makes this more than a fixed list of group names.

The function is called each time the highlights are cleared, so it can return groups that are only known at runtime. The function may return nil or an empty list, in which case no groups are added or excluded. The example:

lua
require("transparent").setup({
  groups = function()
    -- compute groups lazily
    return { "Normal", "NormalNC" }
  end,
  exclude_groups = function()
    return vim.g.transparent_enabled and { "SomeGroup" } or {}
  end,
})

The reason this matters is that highlight groups are not a fixed set. A plugin that registers its groups when it loads, a colour scheme that adds groups conditionally, a file type plugin that adds syntax groups, all of them mean the set of groups with backgrounds is different at any given moment. A static list either misses them or, worse, contains names that do not exist and are silently ignored.

The exclude_groups example is the more interesting one. It reads vim.g.transparent_enabled, which is the plugin's own global flag, and conditionally excludes a group. So a group can be left alone when transparency is on and cleared when it is off, which is the sort of rule that is tedious to express any other way.

The recomputation on every clear also means the plugin stays correct as the editor session goes on, rather than being right only at startup.

clear_prefix handles plugins that invent groups at runtime

The most common complaint about a transparency plugin is that it works until a plugin loads, and then that plugin's panels are opaque again. The reason is that plugins like BufferLineDevIcon and lualine's own icon groups are created dynamically, so no static list can contain them.

The plugin provides a helper function for this, clear_prefix. It will clear all highlight groups starting with the prefix, and the prefix can also be a function, which is called each time to compute the prefix. Returning nil means the prefix is skipped:

lua
require('transparent').clear_prefix(function()
  return 'BufferLine'
end)

For some UI plugins, you may want to clear all highlights, and at this point you should use clear_prefix. The README gives three concrete cases. For akinsho/bufferline.nvim it is require('transparent').clear_prefix('BufferLine'). For nvim-neo-tree/neo-tree.nvim it is clear_prefix('NeoTree'). And for nvim-lualine/lualine.nvim it is clear_prefix('lualine').

The prefix approach is blunt in the right way. A prefix match does not care whether the exact group exists, so it works for the many groups a single plugin generates, and it also means a future version of that plugin which adds a new group is covered without editing your config.

There is a second mechanism for the same problem, the g:transparent_groups global variable. You can add additional highlight groups by explicitly assigning the variable:

lua
vim.g.transparent_groups = vim.list_extend(vim.g.transparent_groups or {}, { "ExtraGroup" })
-- vimscript: let g:transparent_groups = extend(get(g:, 'transparent_groups', []), ["ExtraGroup"])

And the guarantee here is explicit. You can execute this statement anywhere and as many times as you want, without worrying about whether the plugin has already been loaded or not. The README then shows the bufferline example, which maps the bufferline configuration's highlight table into the list with vim.tbl_map over vim.tbl_values, which is the version of this problem you hit when a plugin has a configurable highlight set.

Commands, the enabled flag and one deliberate refusal

The plugin exposes three commands:

code
:TransparentEnable
:TransparentDisable
:TransparentToggle

And it publishes a global variable, g:transparent_enabled, or vim.g.transparent_enabled in Lua. Some plugins and themes support setting transparency themselves, and you can use this variable as a flag, for example require("tokyonight").setup{ transparent = vim.g.transparent_enabled }.

The coordination note is important. The plugin will cache and automatically apply transparency settings, so you only need to call the following commands, which is to say you toggle the flag and the plugin reapplies what it cleared on the next cycle rather than you having to re-run the clearing logic yourself.

That global flag is also why the dynamic exclude_groups example in the README is written the way it is, since a theme that supports its own transparency mode needs to know the current state.

One thing the plugin advises against is making floating windows transparent. The README says it is not recommended to make floating windows transparent, it will look very odd, and everything will be mixed together, and it links to the issues filtered by a float window label for the discussion.

That is a sensible recommendation. A floating window over a translucent background is the case where text legibility actually breaks down, since there is no panel behind the text to give it a solid ground, and a plugin that did it anyway would produce an unreadable editor. The advice for plugin panels is to add their groups to extra_groups instead, with the example naming NormalFloat, for plugins which have float panel such as Lazy, Mason, LspInfo, and NvimTreeNormal for NvimTree.

Where transparent.nvim is the wrong choice

The first limit is scope. It clears backgrounds and nothing else. If the complaint is that the colour scheme itself is ugly in a terminal, that is a colour scheme problem and this plugin will not touch it. It is also the wrong tool for a user who wants a coherent transparent theme, because it leaves you with whatever foregrounds the theme chose, and a theme that was designed for an opaque background often has foregrounds that are too dim against a busy desktop wallpaper.

The second is the installation caveat, which the README flags as a NOTE. Avoid lazy-loading this plugin to ensure the highlight-clearing logic is triggered, and the plugin's function runs quickly. The reason is that a lazily loaded plugin has not run when the editor first draws, so the initial frames are opaque, and if the plugin is never triggered again the transparency is only partial. That is a real constraint for anyone using lazy.nvim, since the plugin has to be in the eager part of the configuration, and it cuts against the lazy-loading habit the rest of a modern Neovim config is built on.

The third is that the work is per plugin. The README's own examples show that bufferline, neo-tree and lualine each need their own clear_prefix call, and the float window FAQ shows that even a new plugin may need an entry. That is maintenance, and it is a maintenance that grows with the number of status line and file tree plugins in a configuration.

The fourth is the ecosystem's fragility. The plugin depends on highlight group names that other plugins and colour schemes are free to rename, and there are no GitHub releases, so there is no version to pin and the repository's last push is the only signal of activity. A configuration that breaks because a status line plugin changed its group names is a small annoyance, but it is one that recurs.

The fifth is that transparent.nvim is a complement, not a replacement. It assumes a colour scheme that already looks good and only removes the paint. A user who needs the whole editor to be legible over an arbitrary background is better served by a theme designed for that, and this plugin is the adjustment layer on top of one.

Editorial conclusion

transparent.nvim suits a Neovim user on a terminal with a translucent or image background who wants the editor to stop painting panels over it, and it is the wrong tool if you want the whole colour scheme to change, because it only clears backgrounds and leaves foregrounds alone. Before installing, read the note about not lazy loading it, since the clearing logic only runs if the plugin is loaded early enough. Verify first which of your plugins define their own highlight groups, because those need either extra_groups entries or a clear_prefix call, and the README lists the common culprits by name.

Frequently asked questions

What does transparent.nvim do?

It removes all background colors to make nvim transparent, by clearing the background of the standard highlight groups. It does not change foreground colors and it is not a colour scheme, so it composes with whatever theme you already use.

How do I configure transparent.nvim?

Normally you do not need to call setup, since the plugin offers g:transparent_groups and the clear_prefix helper as simpler alternatives. When you do, the options are groups, extra_groups and exclude_groups, which each accept a table or a function, plus an on_clear callback that also fires the TransparentClear user event.

What is clear_prefix for?

Some plugins define their highlights dynamically, such as the icon highlights of BufferLineDevIcon or lualine's DevIcon groups, so no static list can contain them. clear_prefix clears every highlight group starting with a prefix, and the prefix can be a function that is called each time, returning nil to skip it.

Can I make floating windows transparent with transparent.nvim?

The README says it is not recommended, because it will look very odd and everything will be mixed together. The advice for plugin panels is to add their groups to extra_groups instead, for example NormalFloat for plugins with float panels and NvimTreeNormal for NvimTree.

Why should I not lazy-load transparent.nvim?

The README notes that you should avoid lazy-loading the plugin to ensure the highlight-clearing logic is triggered, and that the plugin's function runs quickly. The plugin publishes a global flag, g:transparent_enabled or vim.g.transparent_enabled, that themes can read, and it caches and reapplies transparency settings itself.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. xiyaowong/transparent.nvim on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/xiyaowong-transparent-nvim.svg)](https://hysenlabs.com/projects/xiyaowong-transparent-nvim)

Was this useful?