Automatically adapt Zellij Theme to macOS System Appearance
The problem: you switch macOS system appearance to Light/Dark theme, but Zellijβs appearance does not adjust. Sounds familiar? I recently worked around the same problem for Helix.
Apparently, I’m not the only one who is bothering to switch Zellij’s appearance at runtime. There are a couple of GitHub issues discussing the topic from different angles:
- #3277 - Light/Dark theme option and mirroring system setting
- #3831 - Allow automatic light/dark mode detection from applications running within zellij (CSI 2031)
While there is no native solution (yet), I found a fairly reliable workaround that I can use until native support lands on main.
The solution is built around the fact that Zellij automatically reloads on a change in its config file.
Zellij actively watches for changes in theΒ active configuration file. Most fields will be applied immediately without the need for a restart. Otherwise, this will be mentioned in the commentary of the relevant field.
So setting my beloved cattpuccin-frappe
can be achieved in a one liner:
$ sed -i '' -E "s/^theme .*/theme \"$ZELLIJ_THEME\"/" ~/.config/zellij/config.kdl
To automate the switch on system appearance changes, we can use the same tool Neovim people use: dark-notify. It detects when macOS switches between dark and light mode and “informs us”. We can install it via brew:
$ brew install cormacrelf/tap/dark-notify
Now we slightly improve our interface to toggle Zellij theme via a short bash script:
#!/usr/bin/env bash
set -e -u -o pipefail
ZELLIJ_CONFIG_PATH="${HOME}/.config/zellij/config.kdl"
ZELLIJ_THEME_LIGHT="catppuccin-latte"
ZELLIJ_THEME_DARK="catppuccin-frappe"
switch_zellij_theme() {
local theme=$1
if [[ $theme == "light" ]]; then
# Set the light theme
sed -i '' -E "s/^theme .*/theme \"$ZELLIJ_THEME_LIGHT\"/" "$ZELLIJ_CONFIG_PATH"
elif [[ $theme == "dark" ]]; then
# Set the dark theme
sed -i '' -E "s/^theme .*/theme \"$ZELLIJ_THEME_DARK\"/" "$ZELLIJ_CONFIG_PATH"
else
echo "Error: Invalid theme '$theme'. Expected 'light' or 'dark'." >&2
exit 1
fi
}
if [[ $# -eq 0 ]]; then
echo "Error: Missing theme argument." >&2
exit 1
fi
switch_zellij_theme "$1"
Now we need to set a launchd configuration:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>local.cvoigt.dark-notify</string>
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/bin/dark-notify</string>
<string>-c</string>
<string>/Users/c.voigt/go/src/github.com/voigt/dotfiles/themes/toggle_system_appearance.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
Obviously, you will have to adjust the path to your bash script. Please note that the path has to be absolute; relative paths won’t work.
I stored the service in ~/Library/LaunchAgents
as local.cvoigt.dark-notify.plist
.
local.cvoigt.dark-notify.plist
, which means the Label
needs to be local.cvoigt.dark-notify
Finally, load the service and make sure it is listed among the running services.
$ launchctl load ~/Library/LaunchAgents/local.cvoigt.dark-notify.plist
$ launchctl list | grep dark-notify
61513 0 local.cvoigt.dark-notif
Done correctly, your Zellij theme should now adapt within milliseconds to your system’s appearance.