Back to plugins
Keybind Cheatsheet

Keybind Cheatsheet

Universal keyboard shortcuts keymap that automatically detects and displays keybindings for Hyprland, Niri, or MangoWC compositors.

v3.7.1 blacku MIT May 20, 2026

About

Keybind Cheatsheet for Noctalia

Universal keyboard shortcuts cheatsheet plugin for Noctalia that automatically detects your compositor (Hyprland, Niri or MangoWC) and displays your keybindings with recursive config parsing. Supports the classic Hyprland .conf format, the new Hyprland 0.55+ Lua config, Niri KDL and MangoWC.

Preview

Features

  • Automatic compositor detection (Hyprland, Niri, MangoWC)
  • Hyprland Lua config support (Hyprland 0.55+) via hyprctl binds -j
  • Recursive config parsing - follows source (Hyprland .conf), require() (Hyprland Lua) and include (Niri) directives
  • Glob pattern support - parses ~/.config/hypr/*.conf style includes
  • Without Description section - binds with no description are surfaced, not dropped; add a custom description or hide them inline
  • Full per-category color customization - background + text color for every key category, with live preview and clipboard quick-paste
  • Search filter - type to filter keybindings in the panel
  • Configurable paths & parser mode - custom config locations and forced Lua/conf parser in settings
  • Smart key formatting - XF86 keys display as readable names (Vol Up, Bright Down, etc.)
  • Flexible column layout (1-4 columns) with auto-height
  • IPC support - toggle and refresh for global hotkeys

Supported Compositors

Compositor Default Config How it's read
Hyprland 0.55+ ~/.config/hypr/hyprland.lua hyprctl binds -j (live, already-evaluated binds)
Hyprland (classic) ~/.config/hypr/hyprland.conf hyprlang .conf text parser (recursive)
Niri ~/.config/niri/config.kdl KDL parser (recursive include)
MangoWC ~/.config/mango/config.conf bind= / axisbind= / mousebind= parser

Installation

cp -r keybind-cheatsheet ~/.config/noctalia/plugins/

Usage

Bar Widget

Add the plugin to your bar configuration in Noctalia settings. Click the keyboard icon to open the cheatsheet.

Global Hotkey

Hyprland:

bind = $mod, F1, exec, qs -c noctalia-shell ipc call plugin:keybind-cheatsheet toggle

You can set your custom Super key variable (e.g. $mainMod) in the plugin settings.

Niri:

binds {
    Mod+F1 { spawn-sh "qs -c noctalia-shell ipc call plugin:keybind-cheatsheet toggle"; }
}

MangoWC:

bind=SUPER,F1,spawn,qs -c noctalia-shell ipc call plugin:keybind-cheatsheet toggle

IPC Commands

Command Effect
qs -c noctalia-shell ipc call plugin:keybind-cheatsheet toggle Open / close the cheatsheet panel
qs -c noctalia-shell ipc call plugin:keybind-cheatsheet refresh Force a re-parse of your keybindings

refresh is useful after editing your config โ€” bind it to a key to reload without restarting the shell.

Hyprland Lua Config (0.55+)

Hyprland 0.55 replaced the static hyprlang .conf with a Lua config (hyprland.lua). Binds can now be generated with require(), for loops and runtime logic, so they cannot be recovered by reading the file as text.

How it works

Instead of parsing the Lua file, the plugin asks Hyprland directly:

  1. Authoritative bind list โ€” runs hyprctl binds -j and reads the already-evaluated JSON bind list. This correctly handles require() modules, for loops and multi-key chords โ€” whatever Hyprland actually has bound at runtime.
  2. Category & description recovery โ€” the plugin then lightly scans hyprland.lua and every file it pulls in via require() to recover human-readable structure:
    • Category headers: a comment in the form -- N. NAME (e.g. -- 1. Applications)
    • Static descriptions: a description = "..." (or desc = '...') literal maps that exact description to the current category
    • Loop-generated descriptions: a concatenated literal such as description = "Workspace " .. i is treated as a prefix โ€” any bind whose description starts with Workspace is filed under that category
  3. Binds whose description can't be matched fall into a generic Other category; binds with no description at all go to the Without Description section (see below).

You don't need to change your Lua config โ€” just keep using -- N. NAME comment headers and description = "..." fields where you want grouping.

Example Lua structure the scanner understands:

-- 1. Applications
Hyprland.config.bind("$mod, T", function() ... end, { description = "Terminal" })
Hyprland.config.bind("$mod, B", function() ... end, { description = "Browser" })

-- 2. Workspaces
for i = 1, 9 do
  Hyprland.config.bind("$mod, " .. i, function() ... end,
    { description = "Workspace " .. i })   -- prefix "Workspace " -> category "Workspaces"
end

require("keybinds")   -- followed and scanned recursively

Parser mode

A Parser Mode setting controls which Hyprland parser is used:

Mode Behavior
auto (default) Use the Lua parser if hyprland.lua exists, otherwise fall back to the .conf parser
lua Always use hyprctl binds -j (Lua parser)
conf Always use the classic .conf text parser

The legacy hyprlang .conf parser is kept unchanged as a fallback for users still on hyprlang configs.

Without Description Section

Binds with no description are no longer silently dropped. They appear in a dedicated Without Description section where you can:

  • Add a custom description inline โ€” it is remembered and displayed like any other bind
  • Hide a bind you don't care about

Overrides are keyed by a stable bind identity (submap | modmask | key | flags | dispatcher) that deliberately excludes Hyprland's unstable internal Lua registry reference, so your custom descriptions and hidden binds survive Hyprland restarts.

Settings provide a "Show binds without a description" toggle, plus "Restore hidden" and "Clear all overrides" actions.

Config Format

Hyprland (classic .conf)

Recursively parses your main config and all source includes.

# 1. APPLICATIONS
bind = $mainMod, T, exec, alacritty #"Terminal"
bind = $mainMod, B, exec, firefox #"Browser"

# 2. WINDOW MANAGEMENT
bind = $mainMod, Q, killactive, #"Close window"
bind = $mainMod, F, fullscreen, #"Toggle fullscreen"
  • Categories: # N. CATEGORY NAME (N is a number)
  • Descriptions: #"description" at end of the bind line
  • source = ~/.config/hypr/keybinds.conf and globs like source = ~/.config/hypr/apps/*.conf are followed automatically

Niri

Parses the binds { } block and follows all include directives.

binds {
    // #"Applications"
    Mod+T hotkey-overlay-title="Terminal" { spawn "alacritty"; }

    // #"Window Management"
    Mod+Q hotkey-overlay-title="Close window" { close-window; }

    // #"Workspaces"
    Mod+1 { focus-workspace 1; }
}
  • Categories: // #"Category Name" (exact format)
  • Descriptions: hotkey-overlay-title="description" attribute
  • Without descriptions, actions are auto-categorized by type (see table below)
  • include "~/.config/niri/binds.kdl" is followed automatically

MangoWC

Parses bind=, axisbind= and mousebind= directives from ~/.config/mango/config.conf.

# Applications
bind=SUPER,T,spawn,alacritty #"Terminal"
bind=SUPER,B,spawn,firefox #"Browser"

# Window Management
bind=SUPER,Q,killclient, #"Close window"
  • Categories: standalone # Category Name comment lines
  • Descriptions: trailing #"description" on a bind line
  • Modifier aliases recognized: LOGO = SUPER, MOD1 = ALT
  • XF86 media keys are formatted (Vol Up, Mute, Bright Up/Down, โ€ฆ)
  • Lines without a preceding # Category use the localized default category

Auto-Categorization (Niri)

When no category comment is provided, keybindings are grouped by action:

Action prefix Category
spawn Applications
focus-column-* Column Navigation
focus-window-* Window Focus
focus-workspace-* Workspace Navigation
move-column-* Move Columns
move-window-* Move Windows
close-window, fullscreen-window Window Management
maximize-column Column Management
set-column-width Column Width
screenshot* Screenshots
power-off-monitors Power
quit System

Special Key Formatting

Raw Key Display
XF86AudioRaiseVolume Vol Up
XF86AudioLowerVolume Vol Down
XF86AudioMute Mute
XF86MonBrightnessUp Bright Up
XF86MonBrightnessDown Bright Down
Print PrtSc
Prior / Next PgUp / PgDn

Color Customization

Every key category has independently themeable background and text colors: Super, Ctrl, Shift, Alt, XF86, Print, numeric, mouse and default letter keys โ€” plus the description text color.

  • Two-pill rows per category: left pill = background, right pill = label text on that background. Click a pill to open the color picker.
  • Theme-aware defaults: Super / Ctrl / Shift use an empty sentinel meaning "use the Material theme accent" (mPrimary / mSecondary / mTertiary), so themed setups stay untouched unless you deliberately override.
  • Clipboard quick-paste: copy a #RRGGBB / #RRGGBBAA hex and a paste icon appears in each pill โ€” one click applies it (clipboard polled via wl-paste).
  • Live preview + revert: changes preview immediately; closing Settings without Save restores the snapshot taken when the panel opened.
  • Per-row reset and a "Reset all colors" action restore theme defaults.

Settings

Access settings via the gear icon in the panel header:

  • Window width / height (auto or manual) and column count (1-4)
  • Hyprland config path โ€” classic .conf location
  • Hyprland Lua path โ€” hyprland.lua location (0.55+)
  • Parser mode โ€” auto / lua / conf
  • Niri config path / MangoWC config path
  • Show binds without a description toggle + Restore hidden / Clear all overrides
  • Merge sequential binds and split large workspace category (threshold configurable)
  • Per-category colors โ€” background + text for every category, with clipboard paste and reset
  • Refresh โ€” force reload keybindings

Troubleshooting

"Loading..." stays forever

  1. Check the compositor is detected: look for logs tagged [KeybindCheatsheet]
  2. Verify the config file exists at the configured path
  3. On Hyprland 0.55+, confirm hyprctl binds -j works in your terminal

hyprctl error shown in the panel

The Lua parser depends on hyprctl binds -j. Ensure Hyprland is running and hyprctl is on your PATH, or force the classic parser by setting Parser mode to conf.

No categories found

  • Hyprland .conf / MangoWC: categories must be # 1. / # Category Name comment lines
  • Hyprland Lua: add -- N. NAME headers and description = "..." fields in hyprland.lua (and require()d modules)
  • Niri: use // #"Category Name" format

Binds missing or under "Without Description"

On Lua configs, descriptions are matched from description = "..." literals against the live hyprctl binds. Loop-generated binds need a concatenated prefix literal (e.g. "Workspace " .. i). Anything unmatched lands in Without Description, where you can add a description or hide it.

Keybinds from included files not showing

The plugin follows source (Hyprland .conf), require() (Hyprland Lua) and include (Niri) directives automatically. Check logs to see which files are parsed.

Requirements

  • Noctalia Shell 3.6.0+
  • Hyprland (classic .conf or 0.55+ Lua), Niri, or MangoWC
  • hyprctl on PATH for Hyprland Lua configs
  • wl-paste (wl-clipboard) for the color clipboard quick-paste feature

License

MIT