Robin.te.Hofstee

DMenu tutorial

Robin te Hofstee12 min readViews6
DMenu tutorial

dmenu Tutorial: Complete Guide

What is dmenu?

dmenu is a dynamic menu for X, originally designed for dwm. It's a fast, lightweight, and keyboard-driven application launcher and general-purpose menu system. dmenu reads a list of items from stdin and displays them as a menu, allowing you to select one using keyboard input.

Key Features

  • Extremely fast and lightweight (less than 2000 lines of code)
  • Keyboard-driven for efficient workflow
  • Flexible input - accepts any list via stdin
  • Fuzzy matching for quick filtering
  • Highly customizable appearance and behavior
  • Scriptable - can be used in shell scripts for interactive menus

Installation

From Source (Suckless Way)

# Clone the repository
git clone https://git.suckless.org/dmenu
 
# Navigate to directory
cd dmenu
 
# Edit config.h to customize (optional)
vim config.h
 
# Compile and install
sudo make clean install

From Package Manager

# Debian/Ubuntu
sudo apt install dmenu
 
# Arch Linux
sudo pacman -S dmenu
 
# Fedora
sudo dnf install dmenu

Basic Usage

1. Launch dmenu as application launcher

dmenu_run

This shows all executables in your $PATH and launches the selected one.

2. Basic dmenu syntax

echo -e "Option 1\nOption 2\nOption 3" | dmenu

Displays a menu with three options and returns the selected one.

3. Use dmenu output in a script

choice=$(echo -e "Yes\nNo" | dmenu -p "Continue?")
echo "You selected: $choice"

Command-Line Options

OptionDescription
-bDisplay at bottom of screen
-fFast mode (grab keyboard before reading stdin)
-iCase-insensitive matching
-l <lines>Display as vertical list with specified lines
-p <prompt>Set prompt text
-fn <font>Set font
-nb <color>Normal background color
-nf <color>Normal foreground color
-sb <color>Selected background color
-sf <color>Selected foreground color
-w <windowid>Embed into window

Example with options

echo -e "Red\nGreen\nBlue" | dmenu -i -p "Choose color:" -l 10

Keyboard Controls

While dmenu is open:

KeyAction
Type textFilter items
EnterSelect highlighted item
Ctrl+j or DownMove to next item
Ctrl+k or UpMove to previous item
Ctrl+nMove to next item (alternative)
Ctrl+pMove to previous item (alternative)
TabComplete selection
Shift+TabComplete selection (reverse)
Ctrl+yPaste from primary selection
Ctrl+YPaste from clipboard
EscapeCancel/exit
Ctrl+cCancel/exit

Creating dmenu Scripts

Example 1: Simple Yes/No Prompt

#!/bin/bash
 
answer=$(echo -e "Yes\nNo" | dmenu -p "Are you sure?")
 
if [ "$answer" = "Yes" ]; then
    echo "Confirmed!"
else
    echo "Cancelled"
fi

Example 2: Application Launcher Menu

#!/bin/bash
 
choice=$(echo -e "Firefox\nTerminal\nFile Manager\nText Editor" | dmenu -i -p "Launch:")
 
case $choice in
    "Firefox")
        firefox &
        ;;
    "Terminal")
        kitty &
        ;;
    "File Manager")
        pcmanfm &
        ;;
    "Text Editor")
        gedit &
        ;;
esac

Example 3: Power Menu

#!/bin/bash
 
options="Shutdown\nReboot\nLogout\nSuspend\nLock"
 
chosen=$(echo -e "$options" | dmenu -i -p "Power Menu:")
 
case $chosen in
    "Shutdown")
        systemctl poweroff
        ;;
    "Reboot")
        systemctl reboot
        ;;
    "Logout")
        pkill -u "$(whoami)"
        ;;
    "Suspend")
        systemctl suspend
        ;;
    "Lock")
        slock
        ;;
esac

Example 4: WiFi Network Selector

#!/bin/bash
 
# Get list of WiFi networks
networks=$(nmcli -t -f SSID dev wifi list | sort -u)
 
# Show in dmenu
selected=$(echo "$networks" | dmenu -i -l 10 -p "Select WiFi:")
 
# Connect to selected network
if [ -n "$selected" ]; then
    nmcli device wifi connect "$selected"
fi

Example 5: Bookmark Manager

#!/bin/bash
 
# File containing bookmarks (URL | Description format)
bookmarks="$HOME/.config/bookmarks.txt"
 
# Read bookmarks and select one
selection=$(cat "$bookmarks" | dmenu -i -l 20 -p "Bookmark:")
 
# Extract URL (before the |)
url=$(echo "$selection" | cut -d'|' -f1 | xargs)
 
# Open in browser
if [ -n "$url" ]; then
    firefox "$url" &
fi

Bookmarks file format (~/.config/bookmarks.txt):

https://github.com | GitHub
https://reddit.com | Reddit
https://youtube.com | YouTube

Example 6: File Browser

#!/bin/bash
 
# Start in home directory
dir="$HOME"
 
while true; do
    # List directories and files
    choice=$(ls -1p "$dir" | dmenu -i -l 20 -p "Browse: $dir")
    
    # Exit if cancelled
    [ -z "$choice" ] && exit
    
    # Build full path
    fullpath="$dir/$choice"
    
    # If directory, cd into it
    if [ -d "$fullpath" ]; then
        dir="$fullpath"
    # If file, open it
    elif [ -f "$fullpath" ]; then
        xdg-open "$fullpath"
        exit
    fi
done

Example 7: Clipboard History (with clipmenu)

#!/bin/bash
 
# Requires clipmenu package
# This is a pre-built solution that works with dmenu
 
# Store clipboard history
clipmenud &
 
# Show clipboard history
clipmenu

Example 8: Quick Notes

#!/bin/bash
 
notes_dir="$HOME/notes"
mkdir -p "$notes_dir"
 
action=$(echo -e "New Note\nView Note\nDelete Note" | dmenu -p "Notes:")
 
case $action in
    "New Note")
        note_name=$(echo "" | dmenu -p "Note name:")
        [ -n "$note_name" ] && "$EDITOR" "$notes_dir/$note_name.txt"
        ;;
    "View Note")
        note=$(ls -1 "$notes_dir" | dmenu -l 20 -p "Select note:")
        [ -n "$note" ] && "$EDITOR" "$notes_dir/$note"
        ;;
    "Delete Note")
        note=$(ls -1 "$notes_dir" | dmenu -l 20 -p "Delete note:")
        [ -n "$note" ] && rm "$notes_dir/$note"
        ;;
esac

Example 9: Man Page Viewer

#!/bin/bash
 
# Get all man pages
man_page=$(man -k . | awk '{print $1}' | dmenu -i -l 20 -p "Man page:")
 
# Open selected man page in terminal
if [ -n "$man_page" ]; then
    kitty -e man "$man_page"
fi

Example 10: Color Picker

#!/bin/bash
 
color=$(echo -e "#FF0000 Red\n#00FF00 Green\n#0000FF Blue\n#FFFF00 Yellow\n#FF00FF Magenta\n#00FFFF Cyan\n#000000 Black\n#FFFFFF White" | dmenu -i -l 10 -p "Pick color:")
 
# Copy color code to clipboard
color_code=$(echo "$color" | awk '{print $1}')
echo -n "$color_code" | xclip -selection clipboard
 
notify-send "Color copied: $color_code"

Integration with Window Managers

dwm Integration

dmenu is designed for dwm. In dwm's config.h:

static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
 
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },

i3 Integration

Add to ~/.config/i3/config:

bindsym $mod+d exec dmenu_run
bindsym $mod+Shift+d exec /path/to/your/dmenu-script.sh

General Keybinding (with sxhkd)

# In ~/.config/sxhkd/sxhkdrc
super + d
    dmenu_run
 
super + shift + d
    ~/scripts/power-menu.sh

Advanced Tips

1. Custom dmenu_run Wrapper

Create ~/bin/mydmenu:

#!/bin/bash
 
dmenu_run -i -fn "JetBrains Mono-12" -nb "#282828" -nf "#ebdbb2" -sb "#458588" -sf "#ebdbb2" -p "Run:"

2. Use with xargs for Batch Operations

# Select multiple files and delete them
ls | dmenu -l 20 | xargs rm

3. Dynamic Font Sizing

#!/bin/bash
 
# Get screen width
width=$(xrandr | grep '*' | awk '{print $1}' | cut -d'x' -f1 | head -1)
 
# Adjust font based on screen
if [ "$width" -gt 1920 ]; then
    font_size=14
else
    font_size=10
fi
 
dmenu_run -fn "monospace-$font_size"

4. Colorize Output Based on Selection

#!/bin/bash
 
choice=$(echo -e "Success\nWarning\nError" | dmenu -p "Type:")
 
case $choice in
    "Success")
        notify-send -u normal "✓ Success"
        ;;
    "Warning")
        notify-send -u normal "⚠ Warning"
        ;;
    "Error")
        notify-send -u critical "✗ Error"
        ;;
esac

Customization

Edit config.h Before Compiling

/* appearance */
static const char *fonts[] = { "monospace:size=10" };
static const char *prompt = NULL;
static const char *colors[SchemeLast][2] = {
    /*     fg         bg       */
    [SchemeNorm] = { "#bbbbbb", "#222222" },
    [SchemeSel]  = { "#eeeeee", "#005577" },
    [SchemeOut]  = { "#000000", "#00ffff" },
};
 
/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
static unsigned int lines = 0;
 
/* -b option; if 1, dmenu appears at bottom */
static int topbar = 1;

After editing, recompile:

sudo make clean install

Common Use Cases

1. Quick Launcher

dmenu_run -i -p "Run:"

2. Window Switcher (with wmctrl)

wmctrl -l | dmenu -l 10 | awk '{print $1}' | xargs wmctrl -ia

3. Process Killer

ps aux | dmenu -l 20 | awk '{print $2}' | xargs kill

4. SSH Connection Menu

host=$(cat ~/.ssh/config | grep "^Host " | cut -d' ' -f2 | dmenu -p "SSH to:")
[ -n "$host" ] && kitty -e ssh "$host"

5. Screenshot Tool

choice=$(echo -e "Fullscreen\nSelect Area\nCurrent Window" | dmenu -p "Screenshot:")
 
case $choice in
    "Fullscreen")
        scrot ~/Pictures/screenshot.png
        ;;
    "Select Area")
        scrot -s ~/Pictures/screenshot.png
        ;;
    "Current Window")
        scrot -u ~/Pictures/screenshot.png
        ;;
esac

Troubleshooting

dmenu not showing

  • Check if X server is running: echo $DISPLAY
  • Try running with verbose errors: dmenu 2>&1

Wrong colors

  • Check your terminal color settings
  • Verify color codes in config.h or command line

Items not appearing

  • Check if stdin is properly formatted
  • Try: echo -e "test1\ntest2" | dmenu

Font not found

  • Install the font specified in config.h
  • Or change to an installed font: fc-list to see available fonts

Best Practices

  1. Keep scripts simple - dmenu is meant to be lightweight
  2. Use -i flag for case-insensitive matching
  3. Test with echo before using in scripts
  4. Add error handling in scripts
  5. Use meaningful prompts with -p flag
  6. Consider vertical layout (-l) for long lists
  7. Make scripts executable: chmod +x script.sh
  8. Store scripts in ~/bin or ~/.local/bin

Resources


Pro Tip: dmenu is the Swiss Army knife of menus. Anything that outputs text can be turned into an interactive menu with dmenu!

Share this post
Robin te Hofstee

Written by Robin te Hofstee

Technology enthusiast with a deep love for programming. Sharing practical guides on React, Next.js, Linux and self-hosting.