Dashboard Shell
A dashboard shell with a collapsible rail and real routing between views.
DOM + CSS1 dep1 file · 5 KB TSX
Props
// Full, shippable page — real size at normal type scale. The registry
// preview above is a scaled-down miniature of this same composition, not
// a different component.
"use client";
import { useState } from "react";
import { LayoutDashboard, Users, CreditCard, Settings, Search, Bell, PanelLeft } from "lucide-react";
const NAV = [
{ icon: LayoutDashboard, label: "Overview" },
{ icon: Users, label: "Customers" },
{ icon: CreditCard, label: "Billing" },
{ icon: Settings, label: "Settings" },
];
const STATS = [
{ label: "Revenue", value: "$48.2k" },
{ label: "Users", value: "2,318" },
// ---------------------------------------------------------------
// Full source available with a viberdy Pro subscription.
// https://viberdy.dev/pricing
// ---------------------------------------------------------------
}Details
About this page template
A shell's entire job is navigation state: which view is active, whether the rail is collapsed, and how the content region reflows when it changes. A static mockup of a dashboard demonstrates none of that, which is why this was rewritten to actually navigate. Two details are worth copying. The rail collapses by transitioning its width rather than by unmounting its labels — a mount/unmount swap makes the content region jump, while a width transition lets everything beside it reflow continuously. And each nav item keeps its icon in the same position at both widths, so collapsing reads as the labels sliding away rather than as the whole rail being rebuilt; the labels are conditionally rendered but the icon never moves. Every view swaps both the KPI row and the activity list, so switching sections changes real content rather than just a highlight. The collapse control carries aria-expanded and each item carries aria-current, because a rail that communicates state only through background color is unusable in high-contrast mode.


