Sidebar
The Dashboard's primary navigation. Icon-collapsed by default with hover-to-expand, collapsible section labels, and per-item pinning. Sits fixed on the left of every Dashboard screen.
Live preview
<Sidebar defaultSelectedKey="home" />Anatomy
The sidebar collapses to a 48px icon rail; hovering expands it to a 256px overlay with a soft shadow. Clicking the toggle on the right edge pins the expanded state.
- 1Brand mark
Yuno logo. Anchors the top of the rail and stays centered when collapsed.
- 2Section label
Uppercase 10px muted caption (see exception note below). Clicking it collapses the section's items.
- 3Nav item
Icon (Phosphor light) + label. Active state uses sidebar-accent surface + primary text.
- 4Sub-item
Nested list under an item with children. Indented with a border-l divider.
- 5Pin button
Hover-revealed pushpin. Pinned items surface into a PINNED section at the top.
- 6Toggle
Circular button on the right edge. Toggles between icon-only and fully expanded.
Information architecture
The sidebar is organized in four semantic zones. Each zone groups items by how the merchant uses them, not by product taxonomy.
Daily operational surfaces the merchant lands on first. No group header — just the four essentials, always visible.
Foundational configuration that must be in place before a single transaction flows. Collapsed by default so the daily-use rail stays uncluttered.
Optional product surfaces that extend what the merchant can do. Collapsed by default.
Developer and audit tooling, visited less often. Introduced by a divider, no label.
IA rules
- Order by frequency of use first (Home before Insights before Operations), then setup before consumption (Connections before Routing before Checkout builder).
- Max one level of children — no grandchildren. Parents with children are pure expanders; leaf items are the destinations.
- Only leaf items can be pinned. Home, Insights, Reconciliation, and API Reference are non-pinnable — they already sit at surface.
- Section labels are uppercase 10px only for grouping surfaces (CORE SETUP, SOLUTIONS, PINNED). Sentence case everywhere else.
Entry animation
On mount, every element in the sidebar cascades in top-down. The effect is intentional — it draws the eye to Home first and reveals the setup + solutions groups last, hinting at the hierarchy without a heavy header treatment.
| Effect | slide-in-from-left + fade-in (composed) |
|---|---|
| Distance | translateX(-14px) → 0 |
| Curve (slide) | cubic-bezier(0.22, 1, 0.36, 1) |
| Duration (slide) | 500 ms |
| Curve (fade) | ease-out |
| Duration (fade) | 450 ms |
| Stagger — nav items | delay = 120 + index × 30 (ms). Index counts every slot in reading order: separators, section labels, and nav items — the cascade reads as one continuous top-down beat. |
| Stagger — sub-items | delay = childIndex × 30 (ms), reset per parent when it opens. |
| Reduced motion | Honored globally via prefers-reduced-motion in globals.css — animations become instant. |
Tokens involved
- --animate-fade-in — fade-in 0.45s ease-out both
- --animate-slide-in-left — slide-in-from-left 0.5s cubic-bezier(0.22, 1, 0.36, 1) both
Behavior notes
When to use
- As the shell of any Dashboard-adjacent prototype.
- When you need to prototype navigation between multiple product areas (Payments, Rules, Reports…).
- When the flow involves nested destinations (e.g. Operations → Payments, Transactions).
When not to use
- For marketing landing pages — use a top nav.
- For focused single-flow prototypes (wizards, standalone modals) — hide it or use a bare shell.
- For mobile-first prototypes — this sidebar is desktop-only.
Usage
- Wrap it in a fixed container (fixed inset-y-0 left-0 z-30) at the layout level.
- Reserve a 256px content column when expanded, or a 48px one when collapsed.
- Let the user pin frequent destinations — don't hide the pushpin.
- Keep parent items as pure expanders — never route them to a page.
- Don't override Phosphor weights — icons are light (default), fill (active) only.
- Don't add a third state to the toggle — it's binary (collapsed / expanded).
- Don't nest more than one level of children — no grandchildren.
- Don't hardcode section labels in UPPERCASE letterSpacing on top of the built-in styles.
Composition
Sidebar is self-sized (flex flex-col h-full). Position it from the parent layout — usually as a fixed sibling of your page content.
import { Sidebar } from "@/components/organisms/sidebar";
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="min-h-screen">
<div className="fixed inset-y-0 left-0 z-30">
<Sidebar />
</div>
<main className="pl-64">{children}</main>
</div>
);
}Code
<Sidebar
defaultExpanded={false}
defaultSelectedKey="ops-payments"
onSelect={(key, label) => router.push(`/${key}`)}
/>