How I Eliminated Button Hell in Node Management UI — Implementing an Accordion-Style Control Panel
Managing a growing dashboard inevitably leads to one problem: too many buttons.
Techsfree's Dashboard has a node management screen for controlling each server running OpenClaw. It started with just "Restart" and "Backup" buttons. Before I knew it, there were 9 actions: Backup, Restore, Restart, Add Bot, Backup List, Diagnostics, Logs, Retire, Remove Bot.
22 nodes. 22 cards. 9 buttons per card.
Vertical scrolling was a nightmare.
The Problem
The node management UI displays each node as a card. Each card contains:
- Node name, hostname, port
- Running Agent tag list
- Status like disk usage
- Action buttons
The "action buttons" were the problem. In practice, "Restart" and "Backup" are the only frequently-used actions. "Retire" and "Remove Bot" are rarely touched. Yet all 9 buttons were always fully expanded and visible.
/* Before: buttons just laid out in a grid */
.nm-node-actions {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 6px;
}
Solution: Accordion with Default Collapsed State
The fix was simple: add a "⚙️ Actions ▼" toggle button that expands the action panel only when clicked.
HTML Structure
<button class="nm-actions-toggle" onclick="nmToggleActions('${n.id}', this)">
<span>⚙️ Actions</span>
<span class="nm-toggle-arrow">▼</span>
</button>
<div class="nm-actions-body" id="nmActionsBody-${n.id}">
<div class="nm-node-actions">
<!-- action buttons -->
</div>
</div>
CSS
.nm-actions-toggle {
width: 100%;
padding: 5px 0;
background: none;
border: none;
border-top: 1px solid var(--border);
font-size: 11px;
color: var(--muted);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
transition: background 0.15s;
}
.nm-actions-toggle:hover {
background: var(--bg);
color: var(--text);
}
/* Hidden by default */
.nm-actions-body {
display: none;
overflow: hidden;
}
/* Expanded when .open class is present */
.nm-actions-body.open {
display: block;
}
JavaScript
function nmToggleActions(nodeId, btn) {
const body = document.getElementById('nmActionsBody-' + nodeId);
const arrow = btn.querySelector('.nm-toggle-arrow');
if (!body) return;
const isOpen = body.classList.contains('open');
body.classList.toggle('open', !isOpen);
if (arrow) arrow.textContent = isOpen ? '▼' : '▲';
}
Just 20 lines of change, but the impact was significant.
Why Use display: none Instead of Animation?
There are several approaches to accordion implementation:
| Method | Pros | Cons |
|---|---|---|
display: none/block toggle |
Simple, fast | No animation |
max-height animation |
Smooth open/close | Height calculation is tricky, misaligns with dynamic content |
height + overflow
|
Accurate animation | Need to get/set height via JS |
For an admin dashboard, reliability trumps animation. The max-height animation is prone to bugs when content height varies — and in our case, the number of agent tags per node changes dynamically. A simple display toggle was the right call.
Results After Implementation
- Per-card height reduced by ~40%
- All 22 cards visible without painful vertical scrolling
- "Open only when needed" UX reduces accidental clicks
-
▼ / ▲arrows give clear visual state feedback
This pattern works well beyond admin dashboards — card-based UIs with high information density like settings pages, table row expansion, and any dashboard where you want progressive disclosure.
A rough guideline: if there are 3 or fewer buttons, collapsing is unnecessary. At 5 or more, start thinking about it.
Tags: JavaScript, CSS, frontend, UI, accordion, admin-panel, SPA, dashboard, openclaw
Top comments (0)