Open-source project
NStefan002/screenkey.nvim avatar
NStefan002/screenkey.nvim

screenkey.nvim: showing your keystrokes in a floating window for screencasts

Screencast your keys in Neovim

615 stars18 forksLuaMIT

At a glance

What is it?
screenkey.nvim is a Neovim plugin that renders the keys you type into a floating window, the way a system-wide screenkey app does but scoped to the editor. It is useful for live coding and demos, and the main branch is explicitly labelled unstable.
Who is it for?
screenkey.nvim suits anyone who records or streams their editor and wants the audience to see the key sequence rather than guess at it, and it suits a Neovim user on version 0.11 or newer who wants the display scoped to their own editor instead of the whole screen.
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 178 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

It draws keys in Neovim, not your whole screen

screenkey.nvim is a Neovim plugin that displays the keys you are typing in a floating window, just like the screenkey application does, and it points at that project as the model. The scope difference is the whole design. A system-wide display tool captures keystrokes from every application on the desktop, which is why people using those tools worry about accidentally revealing a password typed into a terminal. The README makes that concern its first argument for this plugin, saying that Screenkey will only show pieces of information about your input in Neovim, so a password typed under sudo in a shell is not going to end up on your stream. That is a narrower and more useful guarantee for anyone who lives in the editor. The other two cases the README names are presentation and teaching, where showing the key sequence lets an audience follow along, and live coding sessions, where a newcomer watching you work can see what you are pressing rather than inferring it. The plugin is written in Lua, licensed under MIT, and needs Neovim 0.11.0 or newer, with a Nerd Font listed as optional but recommended.

Installation is a plugin spec, and the main branch is not the stable one

There are three documented installation routes. With lazy.nvim the spec is a small table:

lua
return {
    "NStefan002/screenkey.nvim",
    lazy = false,
    version = "*", -- or branch = "main", to use the latest commit
}

The comment on the version line is the important part, because it points at a choice you have to make deliberately. The spec pins a tag with version = "*", or you can switch to branch = "main" to follow the latest commit. With packer the equivalent is a single line:

lua
use({ "NStefan002/screenkey.nvim", tag = "*" })

And with rocks.nvim the README gives a command rather than a spec, :Rocks install screenkey.nvim, matching the rockspec at the root of the repository, screenkey.nvim-scm-1.rockspec. The README also warns that it tracks the main branch and may include unstable or in-progress features, and tells you to switch to the latest tag release for the stable version, referring to the README in that tag. That warning is consistent with the release history, where the newest tagged version is v2.4.2 from 2024-12-09, after v2.4.1 and v2.4.0, while the last push to the repository was on 2026-04-28. The two dates tell you that substantial work has landed since the last tag, so the choice between a tag and the main branch is a real decision rather than a formality.

The setup call is optional, and the window options are ordinary nvim_open_win values

The README states two things that remove most of the setup work: there is no need to call the setup function, only call it if you need to change some options, and there is no need to lazy load Screenkey because it lazy loads by default. The plugin is therefore usable after installation with no configuration at all. When you do want to configure it, the options are a Lua table passed to require("screenkey").setup, and the first part of it mirrors the arguments of nvim_open_win, since the floating window is a Neovim floating window with the position, size and border options you would expect:

lua
require("screenkey").setup({
    win_opts = {
        row = vim.o.lines - vim.o.cmdheight - 1,
        col = vim.o.columns - 1,
        relative = "editor",
        anchor = "SE",
        width = 40,
        height = 3,
        border = "single",
        title = "Screenkey",
        title_pos = "center",
        style = "minimal",
        focusable = false,
        noautocmd = true,
    },
    hl_groups = {
        ["screenkey.hl.key"] = { link = "Normal" },
        ["screenkey.hl.map"] = { link = "Normal" },
        ["screenkey.hl.sep"] = { link = "Normal" },
    },
    winblend = 0,
    compress_after = 3,
    clear_after = 3,
    emit_events = true,

The table documents that other options from the nvim_open_win help are accepted, such as win, bufpos and zindex, and that the ones listed are only defaults. The three highlight groups exist to colour three different kinds of displayed text, mappings, keys and separators, and they are created with nvim_set_hl. The window sits at the bottom of the editor by default, because the row is computed as vim.o.lines minus vim.o.cmdheight minus 1, with the anchor in the south east corner and the column one short of the right edge.

Compression, clearing and the disable lists are the behaviour knobs

Three options determine how the display behaves over time, and they matter more than they look. compress_after compresses the input when a key is repeated that many times, and the README gives the example that a run of jjjjj becomes j..x4, which keeps a held key from filling the window with identical characters. clear_after clears the input after that many seconds of inactivity, and the documented edge case is that the input is not cleared if the value is below or equal to zero, which is how you keep the display persistent. emit_events toggles User events, described as useful for a custom statusline component, and the README has a section on statusline integration and a table of commands and an API. The disable option takes three lists, filetypes, buftypes and modes, which is how you stop the display from appearing where it makes no sense. That is the mechanism for turning it off in a terminal buffer, in a specific filetype, or in insert mode rather than normal mode, and it is the option to reach for if you are the kind of user who records everything and does not want the overlay appearing in every context. There is also a filter function and a colorize function in the defaults, both of which take the keys and return keys, so you can rewrite what is shown and how it is shown.

Key labels default to Nerd Font glyphs, with plain text for the rest

The keys table maps Neovim key names to what appears in the window, and it is where the Nerd Font recommendation comes from. Control and named keys get readable labels, so TAB, CR and ESC are shown with their own symbols or as Esc, SPACE is shown as a space symbol, and the arrow keys, HOME, END, PAGEUP, PAGEDOWN and INSERT get their own glyphs. The function keys F1 through F12 are mapped to their own Nerd Font symbols, and CTRL and ALT are shown as Ctrl and Alt while SUPER gets a glyph. The leader key is left as the literal <leader> text. If you are not using a Nerd Font, the plugin will fall back to whatever your font renders for those private use area codepoints, which is usually nothing at all, so the display will have gaps in it. That is the practical reason the font is marked optional but recommended, and the reason it is worth checking your font before you record a session. The README also points to a table of key mappings and a rockspec, and the repository holds a doc/ directory, a spec/ directory with a .busted configuration, a .luacheckrc for linting and a stylua.toml for formatting, which tells you the plugin is developed with the usual Lua tooling rather than ad hoc.

A system-wide display tool is the different alternative, with a different trust model

The obvious alternative is the desktop screenkey application the README links to, and the difference between the two is not capability but scope. A system-level tool draws every keystroke from every window on the display, which means it works in a terminal, in a browser form and in your editor, and it also means it captures anything sensitive you type anywhere, which is the problem the plugin's author was trying to avoid. screenkey.nvim deliberately gives that up, showing only what you type inside Neovim. The trade is that a screencast built around the plugin shows a partial picture, and if your workflow includes the terminal for running the application, or a browser for the frontend, the audience loses the keystrokes from those parts of the session. If your recording is mostly inside the editor, the plugin is the more private option. If it is not, the system tool is the more complete one and the password risk has to be managed some other way. There is also a middle option worth naming: several other projects exist for the same goal, and the README has a section listing similar projects, so a reader who wants to compare can do so without guessing. The plugin's own scope is the editor and nothing else, and for a Neovim-first workflow that boundary is a feature rather than a limitation.

Editorial conclusion

screenkey.nvim suits anyone who records or streams their editor and wants the audience to see the key sequence rather than guess at it, and it suits a Neovim user on version 0.11 or newer who wants the display scoped to their own editor instead of the whole screen. It is the wrong choice if you need the display to cover input outside Neovim, and it is the wrong choice if you intend to track the main branch, because the README warns that branch may include unstable or in-progress features and points to the latest tag release for a stable version. Verify first which tag you install, that the Nerd Font glyphs you want are present in your font if you use the default key labels, and that the compress_after and clear_after timers suit the pace of your speaking.

Frequently asked questions

What does screenkey.nvim do in Neovim?

It displays the keys you are typing in a floating window, the way the system screenkey application does, but scoped to Neovim so keystrokes in other applications are not captured. It is meant for screencasts, presentations and live coding sessions.

How do I install screenkey.nvim with lazy.nvim?

Add the spec return { "NStefan002/screenkey.nvim", lazy = false, version = "*" } to your plugin list. The README also gives a packer.nvim line and a rocks.nvim command, :Rocks install screenkey.nvim.

Do I need to call setup to use screenkey.nvim?

No. The README states there is no need to call the setup function unless you want to change some options, and no need to lazy load the plugin because it lazy loads by default.

Is the main branch of screenkey.nvim stable?

The README warns that it tracks the main branch and may include unstable or in-progress features, and tells you to switch to the latest tag release for a stable version. The newest listed tag is v2.4.2 from 2024-12-09, while the last push was on 2026-04-28.

Official sources

  1. Issues
  2. License: MIT
  3. NStefan002/screenkey.nvim on GitHub
  4. README
  5. Releases
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/nstefan002-screenkey-nvim.svg)](https://hysenlabs.com/projects/nstefan002-screenkey-nvim)

Was this useful?