Plan was originally written assuming `transform: rotate` would work in GTK 3 CSS; it doesn't. Spec was already updated in 1646dfc; this brings the plan in line so historical readers see the same approach across spec, plan, and code. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.8 KiB
Waybar Tray Drawer Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Wrap the waybar tray module in a group/drawer so its icons collapse behind a chevron and expand on click.
Architecture: Pure waybar config + CSS — no scripting. The drawer module is built into waybar ≥ 0.10 (installed: 0.15.0). The chevron is a tiny custom/ module rendering one Nerd Font glyph; CSS brightens its color when the drawer enters its expanded state.
Tech Stack: waybar 0.15.0, JetBrainsMono Nerd Font, GTK CSS.
Spec: docs/superpowers/specs/2026-04-30-waybar-tray-drawer-design.md
Verification model: Waybar configs aren't unit-testable. Verification is: (1) JSONC parses, (2) waybar reloads without errors in stderr, (3) visual check that the arrow appears, click expands the tray, click again collapses. Each task ends with a reload + visual check.
Glyph note: The chevron is (`nf-fa-chevron_right`, U+F054). Several editing tools render (U+F053) and `` (U+F054) identically — when copy-pasting, verify the codepoint with python3 -c "print(hex(ord(open('file').read()[OFFSET])))" if anything looks wrong.
File Structure
- Modify:
waybar/config.jsonc— replace"tray"reference inmodules-right, add two new module definitions (group/tray-drawer,custom/tray-arrow). - Modify:
waybar/style.css— add#custom-tray-arrowstyling and a brightened-color rule keyed off the drawer'sexpandedclass.
No new files. No theme changes — reuses existing @tn-fg-muted color variable from theme/colors.css.
Task 1: Wire up the drawer (functional, unstyled)
After this task, clicking the chevron expands/collapses the tray. Arrow looks plain (no rotation, default color) — that's fine, polish comes in Task 2.
Files:
-
Modify:
waybar/config.jsonc(lines 8 and 72-74 in current state) -
Step 1: Replace
"tray"inmodules-rightwith"group/tray-drawer"
In waybar/config.jsonc, change line 8 from:
"modules-right": ["cpu", "temperature", "custom/power-profile", "custom/fan-profile", "pulseaudio", "network", "battery", "custom/mouse-battery", "tray"],
to:
"modules-right": ["cpu", "temperature", "custom/power-profile", "custom/fan-profile", "pulseaudio", "network", "battery", "custom/mouse-battery", "group/tray-drawer"],
- Step 2: Add the
group/tray-drawerandcustom/tray-arrowdefinitions
The existing tray module definition is around lines 72-74:
"tray": {
"spacing": 8
},
Leave that block as-is (the tray module still exists, it's just nested inside the group now). Immediately after the closing } of the tray block (and before the next module), insert:
"group/tray-drawer": {
"orientation": "horizontal",
"drawer": {
"transition-duration": 200,
"transition-left-to-right": true,
"click-to-reveal": true
},
"modules": ["custom/tray-arrow", "tray"]
},
"custom/tray-arrow": {
"format": "",
"tooltip": false
},
- Step 3: Validate JSONC parses
Run:
python3 -c "import json, re, sys; s=open('waybar/config.jsonc').read(); s=re.sub(r'//.*','',s); json.loads(s); print('ok')"
Expected output: ok
If it errors, fix the syntax (most common: trailing comma on last key in an object, or missing comma between objects).
- Step 4: Reload waybar and check stderr
Run waybar in foreground for 3 seconds to capture any startup errors:
pkill waybar; sleep 0.5; timeout 3 waybar 2>&1 | tee /tmp/waybar-check.log; pkill waybar
Expected: no lines containing error, Error, failed, or Failed in /tmp/waybar-check.log related to group/tray-drawer, custom/tray-arrow, or JSON parsing. (Module-not-found warnings for unrelated optional things are fine.)
Then start waybar normally in the background:
nohup waybar >/dev/null 2>&1 &
disown
- Step 5: Visual check
Look at the bar:
- The right edge should now show a chevron glyph (``) where the tray icons used to be.
- Click the chevron → tray icons should slide out to its right.
- Click the chevron again → icons slide back, only chevron remains.
- Existing tray icons (right-click, scroll, etc.) should still respond normally while expanded.
If the chevron renders as a tofu box (), the Nerd Font glyph isn't loading — re-verify the codepoint is U+F054 (see Glyph note in plan header).
- Step 6: Commit
git add waybar/config.jsonc
git commit -m "waybar: collapse tray icons behind a click-to-reveal drawer"
Task 2: Style the chevron (color shift feedback)
After this task, the chevron is muted (matches inactive workspace buttons) and brightens to full foreground when expanded so the user gets visual feedback that the drawer state changed.
Files:
-
Modify:
waybar/style.css(append new rules at end of file) -
Step 1: Append chevron rules to
waybar/style.css
Add to the end of the file (after the existing #temperature.critical rule):
#custom-tray-arrow {
padding: 0 12px;
color: @tn-fg-muted;
transition: color 200ms ease;
}
#group-tray-drawer.expanded #custom-tray-arrow {
color: @tn-fg;
}
The padding: 0 12px matches the existing right-side modules (line 25 of style.css). @tn-fg-muted matches the unfocused-workspace color (line 15) — the arrow reads as a control, not a status icon. When the drawer is open, the arrow brightens to @tn-fg (full foreground) over 200 ms — same duration as the drawer's slide.
Note: An earlier draft of this plan used
transform: rotate(180deg)for visual feedback. GTK 3 CSS (which waybar uses) treatstransformas a fatal parse error, so the rotation approach was replaced with a color shift — matching the existing convention instyle.cssfor state feedback (battery/cpu/temperature).
- Step 2: Reload waybar
pkill -SIGUSR2 waybar
(SIGUSR2 reloads config + CSS without restarting; same signal already used elsewhere in this repo.)
-
Step 3: Visual check
-
Chevron is muted (matches the unfocused workspace button color).
-
Click it → tray slides in and the chevron brightens to full foreground.
-
Click again → tray collapses and the chevron dims back.
-
Spacing around the chevron looks consistent with neighboring modules.
If the color shift doesn't happen, the GTK class name on the expanded group might differ. Inspect with:
GTK_DEBUG=interactive waybar &
…then in the GTK Inspector, click the chevron in expanded state and check what class is applied to the parent group (should be expanded; if it's something else like revealed, update the CSS selector to match).
- Step 4: Commit
git add waybar/style.css
git commit -m "waybar: style tray drawer chevron with color-shift feedback"
Final verification
- Bar starts cleanly on next login. Log out and back in (or restart niri), confirm the bar comes up with the drawer collapsed by default and no errors in
journalctl --user -u waybar(if waybar is run as a user unit) ornohup.out(if started by niri config). - No regressions on other modules. Workspaces, clock, cpu/temp, audio, network, battery, mouse battery all render and respond to clicks/scrolls as before.
- Spec requirements satisfied:
- Default state collapsed ✓ (drawer's default behavior)
- Click-to-toggle ✓ (
click-to-reveal: true) - 200 ms slide animation ✓ (
transition-duration: 200) - Tray icons retain their normal interactions ✓ (drawer doesn't intercept events on revealed children)
- No state persistence across waybar restarts ✓ (drawer always starts collapsed — no persistence layer added)