StealThis .dev
Pages Medium

Dashboard — List + detail (master-detail)

A polished master-detail dashboard for a fictional SaaS CRM: a scrollable left list of customers with avatars, status badges and mini metrics, beside a rich right pane showing the selected account header, four KPI tiles with deltas and inline-SVG sparklines, an animated bar chart, a spend donut, and an activity timeline. Clicking or arrow-keying a row selects it; live search and status filters narrow the list; on mobile the detail slides in full-screen with a back button. Vanilla JS, no libraries.

Open in Lab
html css vanilla-js
Targets: JS HTML

Code

List + detail (master-detail)

A two-pane master-detail layout for a fictional SaaS CRM (Nimbusly). The left column is a scrollable list of customers — each row shows an avatar, name, a status badge (Active / Trial / At risk) and a mini MRR metric with an up/down delta. A search box filters the list live and a segmented control filters by status. The right pane renders the selected account: a header with avatar, plan and location, four KPI tiles (MRR, seats used, health score, open tickets) each with a delta and inline-SVG sparkline, an animated SVG bar chart that toggles between API calls and storage, a spend-mix donut, and a vertical activity timeline.

Selection is fully keyboard-driven: the list is an ARIA listbox, rows carry role="option" with aria-selected, and Up/Down/Home/End move the selection while keeping the chosen row scrolled into view. Clicking or pressing Enter selects a row, repaints every detail widget, and animates the bars and donut into place. The open-tickets KPI ticks on a timer to simulate live data, and an “Add note” action prepends an entry to the timeline.

Below ~720px the layout collapses to a single column: the icon rail hides, the list fills the screen, and selecting a row pushes a full-screen detail view with a Back button that returns focus to the originating row. Charts are pure inline SVG and CSS with no libraries, landmarks (nav / main / header) and focus-visible states keep it accessible, and a small toast() helper confirms actions.