Configure Neovim – Distraction-Free Coding with zen-mode.nvim

Published on Mar 20, 2026

Configure Neovim – Distraction-Free Coding with zen-mode.nvim

There are days when the editor itself gets in the way. The statusline, the gutter with its line numbers and git signs, the file tree on the left, the diagnostic virtual text floating at the end of every line — all of it is useful most of the time, but sometimes you just want to look at the code. No decorations, no interruptions, just the text in front of you.

That is what zen-mode.nvim is for. It is a plugin by folke — the same person behind which-key.nvim, trouble.nvim, and lazy.nvim — that hides all the surrounding UI when you ask it to, opens your current buffer in a centred floating window, and restores everything exactly as it was when you close it. You press one key to enter, you press the same key to leave. Nothing is permanently changed.

We will also be setting up twilight.nvim, which pairs naturally with zen mode. While zen mode handles the surrounding UI, twilight dims the parts of the buffer you are not actively working on, leaving only the current function or block at full brightness. Together the two plugins create a focused coding environment that is genuinely different from using the editor normally.


Prerequisites

There are no hard dependencies from previous posts for this one. If you have been following the series, your Lazy.nvim setup and plugin folder structure are already in place. If you are dropping in on this post specifically, all you need is Lazy.nvim and nvim-treesitter installed. Twilight uses Treesitter to understand the structure of your code, so it knows which block the cursor is currently inside.


How the Two Plugins Work Together

It is worth being clear about what each plugin does before we write any configuration.

  • zen-mode.nvim opens a new floating window that occupies a fixed width in the centre of your screen. The area outside the window is dimmed by a configurable backdrop. The surrounding UI — the statusline, the signcolumn, the command line ruler — is hidden for the duration. When you close zen mode, the floating window is dismissed and every option that was changed is restored to its previous value. The rest of your open buffers and split layout are untouched and waiting for you when you return.

  • twilight.nvim works entirely within the buffer, regardless of whether zen mode is active or not. It uses Treesitter to identify the top-level block that the cursor currently sits inside — a function definition, a class, a table — and keeps that block at full brightness while dimming everything above and below it. As you move the cursor to a different block, the dimming follows. When zen mode is active and twilight is installed, zen mode enables twilight automatically so the two work as one.


Installing the Plugins

Inside lua/plugins/, create a new file called zen.lua.

-- lua/plugins/zen.lua

return {
  -- Distraction-free writing environment
  {
    "folke/zen-mode.nvim",
    cmd = "ZenMode",
    keys = {
      {
        "<leader>z",
        "<cmd>ZenMode<cr>",
        desc = "Toggle zen mode",
      },
    },
    opts = {},
  },

  -- Dims inactive portions of code using Treesitter
  {
    "folke/twilight.nvim",
    cmd = { "Twilight", "TwilightEnable", "TwilightDisable" },
    opts = {},
  },
}

Save the file and run :Lazy sync. Both plugins will be installed. Press <leader>z to test immediately. Your buffer should move into a centred floating window with the rest of the screen dimmed around it.


Configuring zen-mode.nvim

The default configuration is fine for a first look, but there is quite a lot we can tune to make it feel exactly right. Let us go through the options that matter.

opts = {
  window = {
    -- shade the area outside the zen window
    -- 0 is fully transparent, 1 is the same as the Normal background
    backdrop = 0.90,

    -- width of the zen window in columns
    -- numbers above 1 are absolute column counts
    -- numbers below 1 are a fraction of the editor width
    width = 100,

    -- height stays at 1 (full height) by default
    height = 1,

    -- window-local options to apply inside the zen window
    options = {
      signcolumn    = "no",   -- hide the git and diagnostic signs
      number        = false,  -- hide line numbers
      relativenumber = false, -- hide relative line numbers
      cursorline    = false,  -- hide the cursor line highlight
      foldcolumn    = "0",    -- hide the fold column
      list          = false,  -- hide whitespace characters
    },
  },

  plugins = {
    -- enable twilight dimming automatically when zen mode opens
    twilight = { enabled = true },

    -- hide git signs while in zen mode
    gitsigns = { enabled = false },

    -- hide diagnostics while in zen mode
    diagnostics = { enabled = false },

    -- hide global options like the ruler and showcmd
    options = {
      enabled    = true,
      ruler      = false,
      showcmd    = false,
      laststatus = 0,  -- hide the statusline
    },
  },
},

The window.options table is particularly useful. Any Neovim window-local option (vim.wo.*) can go in here. The options are applied when zen mode opens and reversed when it closes. We are hiding the signcolumn, line numbers, relative numbers, the cursor line, the fold column, and the whitespace list characters — all things that are helpful during development but distracting when you want to read or write without interruption.

The plugins table tells zen mode which other plugins to adjust when it activates. Disabling gitsigns clears the added/changed/removed markers from the gutter. Disabling diagnostics hides the LSP underlines and virtual text. Setting laststatus = 0 makes the statusline disappear entirely. All of these are restored the moment you leave zen mode.


Configuring twilight.nvim

Twilight works well with its defaults, but a couple of options are worth adjusting.

opts = {
  dimming = {
    -- how dim the inactive code should be (0.0 is invisible, 1.0 is normal)
    alpha = 0.25,
    -- whether to use the background colour for dimming in addition to the foreground
    color = { "Normal", "#ffffff" },
    term_bg = "#000000",
    -- set this to true to dim invisible characters too
    inactive = false,
  },
  context = 10, -- how many lines of context to show beyond the active block
  treesitter = true, -- use Treesitter for smarter block detection
  expand = {
    -- node types to always show in full even if they are not the active block
    "function",
    "method",
    "table",
    "if_statement",
  },
},

The alpha value controls how visible the dimmed code is. The default of 0.25 is quite subtle — if you want a stronger effect, try 0.15. The context setting adds a buffer of lines above and below the active block so the transition does not feel too sharp.

The expand list tells Treesitter which node types should always be shown in full when they are the active block. By default this includes functions, methods, tables, and if statements, which covers most of what you will be working in.

You can use twilight independently of zen mode too. :Twilight toggles the dimming without entering zen mode, :TwilightEnable turns it on permanently, and :TwilightDisable turns it off.


Callbacks for Deeper Customisation

zen-mode.nvim has on_open and on_close callbacks that fire when zen mode activates and deactivates. These are useful if you want to adjust things that are not covered by the built-in plugins table — for example, disabling the completion menu while in zen mode or changing the colorscheme temporarily.

opts = {
  -- ... window and plugins config from above ...

  on_open = function(win)
    -- disable blink.cmp while in zen mode
    vim.b.completion = false
  end,

  on_close = function()
    -- re-enable blink.cmp when zen mode closes
    vim.b.completion = true
  end,
},

The win parameter passed to on_open is the window ID of the zen floating window. You can use it with vim.api.nvim_win_set_option if you need to apply options that are not in the standard window.options table.


Putting It All Together

Here is the complete lua/plugins/zen.lua:

-- lua/plugins/zen.lua

return {
  -- Distraction-free writing environment
  {
    "folke/zen-mode.nvim",
    cmd = "ZenMode",
    keys = {
      {
        "<leader>z",
        "<cmd>ZenMode<cr>",
        desc = "Toggle zen mode",
      },
    },
    opts = {
      window = {
        backdrop = 0.90,
        width    = 100,
        height   = 1,
        options  = {
          signcolumn     = "no",
          number         = false,
          relativenumber = false,
          cursorline     = false,
          foldcolumn     = "0",
          list           = false,
        },
      },
      plugins = {
        twilight    = { enabled = true },
        gitsigns    = { enabled = false },
        diagnostics = { enabled = false },
        options     = {
          enabled    = true,
          ruler      = false,
          showcmd    = false,
          laststatus = 0,
        },
      },
      on_open = function(_win)
        vim.b.completion = false
      end,
      on_close = function()
        vim.b.completion = true
      end,
    },
  },

  -- Dims inactive code blocks using Treesitter
  {
    "folke/twilight.nvim",
    cmd = { "Twilight", "TwilightEnable", "TwilightDisable" },
    opts = {
      dimming = {
        alpha    = 0.25,
        color    = { "Normal", "#ffffff" },
        inactive = false,
      },
      context   = 10,
      treesitter = true,
      expand     = {
        "function",
        "method",
        "table",
        "if_statement",
      },
    },
  },
}

Verifying the Setup

Restart Neovim and open any file. Press <leader>z. The buffer should slide into a centred floating window, line numbers and git signs should disappear, the statusline should hide, and the code outside the current function block should dim. Press <leader>z again to exit. Everything should be back exactly as you left it.

If twilight is not dimming, check that nvim-treesitter is installed and that a parser is installed for the current filetype. You can install Treesitter parsers with :TSInstall <language> — for example :TSInstall lua for Lua files.


Wrapping Up

zen-mode.nvim and twilight.nvim are small additions to the config but they change the feel of the editor in a meaningful way. Not every session calls for them, but when you want to read through a complex function carefully or write something without distractions, having them available with a single keypress makes a real difference.

This wraps up the core of our Neovim setup. We now have a plugin manager, a statusline, a file explorer, git integration, an LSP, autocompletion, formatting, and a focused writing mode. In future posts we will look at some of the extra plugins that round the experience out further — things like Treesitter, a fuzzy finder, and a terminal integration.

To find the rest of my posts on Neovim, click here.

Author Information

aeon501
aeon501

Web Developer, Restless. My mind goes on epic voyages, then return back to reality. I write about things I have experienced in my coding journey.

View all posts
Advertisement
Ad placeholder
Sponsored
Ad 2