modes.nvim paints the whole line in the colour of the mode you are in
Prismatic line decorations for the adventurous vim user
At a glance
- What is it?
- modes.nvim is a small Neovim plugin that colours the current line according to the Vim mode, with separate highlight groups per mode and options for the cursor, line numbers and sign column. It is a tasteful visual cue, and it competes with your colour scheme for the same pixels.
- Who is it for?
- Adopt modes.nvim if you lose track of which mode you are in during long editing sessions, if you use a colour scheme that will not fight it, and if you are willing to tune the eight Modes highlight groups against your own theme. Do not adopt it if you already have a statusline mode indicator, if a heavily decorated colour scheme is what you want, or if your plugin set includes Which Key, because the d and y operators will lose their highlight there.
- 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 74 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 mode indicator is a background colour, not a text badge
The project describes itself as prismatic line decorations for the adventurous vim user, and the mechanism is simple to state: instead of changing a small indicator, the plugin colours the background of the entire current line according to the Vim mode you are in.
Insert mode gets one colour, visual mode another, and each mode that can change text gets its own. The visual result is that the editing area itself is the mode display, so there is nothing to look away from and nothing to read.
The implementation is Lua, the primary language recorded for the repository, and the plugin is distributed as a standard Neovim plugin with a setup function. The usage block in the README is the familiar lazy.nvim style spec:
{
"mvllow/modes.nvim",
tag = "v0.2.1",
config = function()
require("modes").setup()
end
}Two things are worth reading off that snippet. The plugin is configured through a single setup call, and the README pins a tag rather than tracking the branch, so a reader who copies it verbatim gets a fixed version.
The stated requirement is Neovim 0.11 or later. That is a hard floor rather than a soft preference, and it will rule out older Neovim installations outright, which is a common reason a plugin like this is not usable in an environment pinned to an older editor version.
Eight highlight groups decide what each mode looks like
The colour scheme is expressed as eight Vim highlight groups, and the README tabulates their default values. ModesCopy carries guibg=#f5c359, ModesDelete guibg=#c75c6a, ModesFormat guibg=#c79585, ModesInsert guibg=#78ccc5, ModesReplace guibg=#245361, ModesVisual guibg=#9745be, ModesChange falls back to ModesDelete, and ModesSelect falls back to ModesVisual.
Those two fallbacks are a design decision rather than an oversight. Change mode is a variation on delete, since both are destructive, and select is a variation on visual, since selecting text is what visual mode is for. If you disagree, the option table lets you set them independently.
Because these are ordinary highlight groups, they can be redefined by a colour scheme, and the plugin's defaults will fight a scheme that has opinions about the same groups. That is the central trade-off of the plugin: it takes over the background of every line you edit, and a scheme designed to keep the editing area quiet will not enjoy that.
The setup options mirror the same structure, with a colors table holding one entry per mode:
require('modes').setup({
colors = {
bg = "", -- Optional bg param, defaults to Normal hl group
copy = "#f5c359",
delete = "#c75c6a",
change = "#c75c6a", -- Optional param, defaults to delete
format = "#c79585",
insert = "#78ccc5",
replace = "#245361",
select = "#9745be", -- Optional param, defaults to visual
visual = "#9745be",
},
})The bg entry is the escape hatch. Left empty it defaults to the Normal highlight group, which means the plugin follows your theme's background colour; set it and you pin the base colour the mode tints are applied over.
Cursor, line numbers and the sign column can be tinted to match
Most of the remaining options decide how much of the editor chrome gets dragged along with the mode colour.
set_cursor enables the cursor highlight, so the cursor itself carries the mode colour rather than the block colour of your scheme. set_cursorline enables the cursorline, and the README is specific that this also disables the cursorline for inactive windows or for ignored filetypes, which keeps a background window from showing a stale mode colour. set_number enables line number highlights to match the cursorline, and set_signcolumn does the same for the sign column.
The reason to wire all three together is coherence. A mode colour on the line while the number column and the sign column stay in their normal colours looks like a rendering bug rather than a deliberate state. Tinting them together makes the whole column read as one signal.
Then there is line_opacity, which sets the opacity for the cursorline and number background, with the default at 0.15. A low opacity keeps the mode readable without turning the editing area into a solid block of colour, which matters most in insert mode where you spend most of your time.
Each of these switches is independent, so a minimal configuration is possible: mode tints on, cursor and column highlights off. The README does not document a preset system or a per-mode granularity beyond this, which means the tuning is manual and it is on you to find a combination that does not fatigue you over a full day.
The ignore list can be a filetype list or a function
Not every buffer deserves a mode colour, and the ignore option is where you say so. The documented value is a list of filetypes:
ignore = { "NvimTree", "TelescopePrompt", "!minifiles" }The README explains the semantics, and the exclamation mark is the part that is easy to miss. A plain entry disables mode highlights for that filetype. An entry prefixed with ! does the opposite, enabling mode highlights for a filetype that would otherwise be disabled. The wording is careful here: enable with the prefix if otherwise disabled, and it asks for pull requests with common patterns.
That default list is a good summary of the use case. NvimTree and TelescopePrompt are picker and file-tree buffers where you are typing a query, not editing, so painting the line by mode adds nothing. The minifiles entry with the prefix shows the override in action, because minifiles is disabled by default and this turns it back on.
The option can also be a function, described as fun():boolean that disables modes highlights when true. That form moves the decision from a static list into live logic, so a plugin can suppress the highlighting in a particular context, such as while a floating window is open, rather than for a whole filetype.
The mechanism is worth understanding because it is the difference between a static decoration and something that can respond to state. It is also the only part of the configuration that can be changed at runtime, and the README gives no example function, so you are left to write one against the documented signature.
Which Key wins the d and y operators, and there is a documented workaround
The README has a known issues section, and it names one conflict precisely: some Which Key presets conflict with this plugin, and the d and y operators will not apply highlights if there are d and y prefixes hooked by Which Key, because Which Key takes priority.
This is a real failure mode rather than a cosmetic quibble. In operator-pending mode you are about to delete or yank, and the mode colour is exactly the signal you want at that moment, which is the moment the plugin goes quiet.
The workaround is given as configuration for Which Key itself:
require("which-key").setup({
triggers_blacklist = {
n = { "d", "y" }
}
})Blacklisting the d and y triggers in normal mode stops Which Key from claiming them, and the plugin's operator-pending highlight comes back. The trade-off is that you lose the Which Key popup for those two keys, which for some people is a good trade and for others is not.
This one issue also tells you something about the plugin's compatibility surface. modes.nvim works by observing mode changes and painting lines, so anything that changes mode or remaps keys in that area can interfere. Which Key is only the conflict the README names, but the pattern suggests the class of interaction to expect: other mode-aware or operator-aware plugins may need similar attention.
Tests run headless through plenary, docs through mini.doc
The repository is small and the tooling is visible. The top level holds lua/ for the plugin, doc/ for generated documentation, scripts/, tests/ and a Makefile, plus a .stylua.toml for formatting and an .editorconfig.
The Makefile shows how the project is developed. Tests run in a headless Neovim started with nvim --headless --noplugin --clean and a minimal init file, calling a Test() function, and the dependency step clones plenary.nvim into a vendor pack directory if it is not already there. The docs target runs the mini.doc generator against scripts/minidoc.lua, and the README gives the in-editor equivalent:
:luafile scripts/minidoc.luaThe README asks for make docs, or that command inside Neovim with mini.doc in the runtimepath, and points contributors at the mini.doc project for the tooling itself. Documentation is therefore generated from annotations in the source rather than written by hand, which is why the doc/ directory exists at all.
On release practice, there is a small inconsistency worth noticing. The release list shows v0.3.0 published on 2025-05-27, after v0.2.1 in 2023, yet the usage snippet in the README still pins tag = "v0.2.1". The repository is not archived and the last push was on 2026-08-10, so work is continuing, but the documented install path is behind the newest tag. Anyone copying that block verbatim gets the older version, and anyone tracking the branch gets something the README does not describe.
Editorial conclusion
Adopt modes.nvim if you lose track of which mode you are in during long editing sessions, if you use a colour scheme that will not fight it, and if you are willing to tune the eight Modes highlight groups against your own theme. Do not adopt it if you already have a statusline mode indicator, if a heavily decorated colour scheme is what you want, or if your plugin set includes Which Key, because the d and y operators will lose their highlight there. Before pinning a version, note that the README still shows the tag v0.2.1 while v0.3.0 was released on 2025-05-27, and the last push was on 2026-08-10.
Frequently asked questions
How do I install modes.nvim in Neovim?
The README gives a lazy.nvim style spec with the plugin name mvllow/modes.nvim, a pinned tag of v0.2.1 and a config function calling require("modes").setup(). The stated requirement is Neovim 0.11 or later.
How do I change the colours modes.nvim uses for each mode?
Pass a colors table to setup with one entry per mode, for example copy, delete, change, format, insert, replace, select and visual, plus an optional bg entry that defaults to the Normal highlight group. The plugin also defines its own highlight groups, ModesCopy through ModesVisual, which a colour scheme can override.
Why do the d and y operators not show a mode highlight with modes.nvim?
The README says some Which Key presets conflict with the plugin, and the d and y operators will not apply highlights when Which Key hooks those prefixes, because Which Key takes priority. The documented fix is to blacklist them in the Which Key setup with triggers_blacklist set to n = { "d", "y" }.
Can modes.nvim skip highlighting in some buffers?
Yes. The ignore option takes a list of filetypes to disable mode highlights for, with a prefix of ! to enable them where they would otherwise be disabled, for example ignore = { "NvimTree", "TelescopePrompt", "!minifiles" }. It can also be a function returning a boolean that disables the highlights when true.
Official sources
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.
[](https://hysenlabs.com/projects/mvllow-modes-nvim)Was this useful?