GODRICH
#css-animation#button#loader#transition#scroll#dashboard#ui#design-trends

Dashboard Sidebar Design + 9 Widget UI Pieces

Here, a dashboard sidebar design means just this one piece, not the whole admin page — plus eight more standalone dashboard widgets, including a donut chart

Auto-plays · click a tile to jump to its section · all nine in one zip

These nine are ordered by where your eye lands on a real screen, not by popularity. First the structural piece (sidebar), then the at-a-glance summaries (stats, table, chart), then the pieces a visitor actually touches (filters, empty state, settings), and last the two small popovers tucked in a header corner (notifications, user menu). Every demo drops just that one widget in the middle of the frame — no surrounding admin chrome — so you can lift the exact markup into whatever page you already have. The same dashboard pillar recut around stat cards is 9 Dashboard Components, and the pieces meant to be pasted into a blog page are the embed widgets. Splitting at widget scale is deliberate: swapping one missing piece into a screen you already have happens far more often in real projects than adopting a whole new admin template.

01Standalone sidebar nav

What moves

Click the collapse button and the dashboard sidebar design ui actually shrinks from 208px to 76px while the text labels fade out and only the icons stay.

Standalone sidebar nav
Open in a new tab

01 · Standalone sidebar nav — Measured area 12.547% · moving frames 13/23Original by GODRICH · SCSS and React ship in the zip · See the password

widtharia-pressedclick

In the code

The current page is marked with a thin left bar and a soft background tint.

.sd { width: 208px; transition: width $duration $easing; }
.sd.is-collapsed { width: 76px; }
.sd__label { transition: opacity $duration $easing; }
.sd.is-collapsed .sd__label { opacity: 0; }

02Stat card row with sparkline reveal

What moves

Switch the period toggle and all three numbers actually swap.

Stat card row with sparkline reveal
Open in a new tab

02 · Stat card row with sparkline reveal — Measured area 0.374% · moving frames 15/23Original by GODRICH · SCSS and React ship in the zip · See the password

stroke-dashoffsetopacitymouseenter

In the code

Each mini chart line underneath uses an SVG pathLength of 100, so the same dash-offset math draws any shape the same way.

.sc__spark-path { stroke-dasharray: 100; stroke-dashoffset: 100; }
.sc__card.is-demo .sc__spark-path { animation: sc-draw 2s $easing infinite; }
@keyframes sc-draw {
  0%  { stroke-dashoffset: 100; }
  60% { stroke-dashoffset: 0; }
}

03Sortable mini table

What moves

Click a column header and the rows are actually re-sorted in the DOM, not just visually reordered with CSS.

Sortable mini table
Open in a new tab

03 · Sortable mini table — Measured area 54.986% · moving frames 23/23Original by GODRICH · SCSS and React ship in the zip · See the password

clickaria-sortorder

In the code

The amount column compares numbers; the name column compares strings.

rows.sort(function (a, b) {
  var av = a.dataset[key], bv = b.dataset[key];
  if (key === 'amount') { av = Number(av); bv = Number(bv); return (av - bv) * dir; }
  return av.localeCompare(bv) * dir;
});
rows.forEach(function (r) { tbody.appendChild(r); });

04Donut chart card with center counter

What moves

Toggle a legend item and that slice actually drops out of the ring while the center number counts to the new total.

Donut chart card with center counter
Open in a new tab

04 · Donut chart card with center counter — Measured area 2.739% · moving frames 16/23Original by GODRICH · SCSS and React ship in the zip · See the password

@propertyconic-gradientclick

In the code

The ring itself is plain conic-gradient, no SVG at all.

@property --pct-a { syntax: "<percentage>"; inherits: true; initial-value: 0%; }
.cc__ring {
  background: conic-gradient($color 0 var(--pct-a), $stage-yellow var(--pct-a) var(--pct-b), rgba(23,20,26,.08) var(--pct-b) 100%);
  mask: radial-gradient(farthest-side, transparent 60%, #000 61%);
  transition: --pct-a $duration $easing, --pct-b $duration $easing;
}

05Chip filter bar

What moves

Every chip you click actually flips to a pressed state (filled pill, aria-pressed="true") and the selected count updates.

Chip filter bar
Open in a new tab

05 · Chip filter bar — Measured area 5.824% · moving frames 23/23Original by GODRICH · SCSS and React ship in the zip · See the password

aria-pressedtransformclick

In the code

A "clear all" text button only shows up once something is selected.

c.addEventListener('click', function () {
  c.classList.remove('is-demo');
  var on = c.getAttribute('aria-pressed') === 'true';
  c.setAttribute('aria-pressed', String(!on));
  refresh();
});

06Empty state with add-morph

What moves

A shape-only illustration floats gently until you click "add first item" — then that same spot actually morphs into one real list card.

Empty state with add-morph
Open in a new tab

06 · Empty state with add-morph — Measured area 24.73% · moving frames 13/23Original by GODRICH · SCSS and React ship in the zip · See the password

transformopacityclick

In the code

Click again and it morphs back.

.es__empty, .es__item { position: absolute; inset: 0; transition: opacity $duration $easing, transform $duration $easing; }
.es__item { opacity: 0; transform: scale(.9); }
.es.is-added .es__item { opacity: 1; transform: scale(1); }
.es.is-added .es__empty { opacity: 0; transform: scale(.9); }

07Settings form section with save state

What moves

Flip a toggle, hit save, and the button actually cycles through three states — a spinning ring, then a green "saved" state 700ms later, reverting after 1.6s.

Settings form section with save state
Open in a new tab

07 · Settings form section with save state — Measured area 0.167% · moving frames 10/23Original by GODRICH · SCSS and React ship in the zip · See the password

transitionaria-checkedclick

In the code

It's one closed <form>, meant to be lifted as a section, not a whole settings page.

save.classList.add('is-busy'); label.textContent = 'Saving';
setTimeout(function () {
  save.classList.remove('is-busy'); save.classList.add('is-done'); label.textContent = 'Saved';
  setTimeout(function () { save.classList.remove('is-done'); label.textContent = 'Save'; }, 1600);
}, 700);

08Notifications dropdown panel

What moves

Click the bell and the panel actually grows open from that corner.

Notifications dropdown panel
Open in a new tab

08 · Notifications dropdown panel — Measured area 5.662% · moving frames 9/23Original by GODRICH · SCSS and React ship in the zip · See the password

transform-originaria-expandedclick

In the code

Click one notification and only that row is marked read while the badge count drops by exactly one.

function syncBadge() {
  var n = document.querySelectorAll('.np__item.is-unread').length;
  badge.textContent = String(n);
  badge.style.display = n > 0 ? '' : 'none';
}
it.addEventListener('click', function () { it.classList.remove('is-unread'); syncBadge(); });

09User avatar dropdown menu

What moves

Click the avatar and the menu actually opens anchored to the top-right corner.

User avatar dropdown menu
Open in a new tab

09 · User avatar dropdown menu — Measured area 28.833% · moving frames 10/23Original by GODRICH · SCSS and React ship in the zip · See the password

transformEscapeclick

In the code

Click anywhere outside, or press Escape, and it actually closes — clicking inside the menu itself does not.

document.addEventListener('click', function (e) {
  if (!e.target.closest('.um')) close();
});
document.addEventListener('keydown', function (e) { if (e.key === 'Escape') close(); });

Where it breaks — the trap

dashboard widget design — where does it break?

The real trap across these nine was vertical position on the two popovers (notifications, user menu). The stage centers content in a 480×300 frame, so the bell or avatar landed dead center — and the panel opening downward from there ran straight past the bottom edge, forcing a scrollbar. Anchoring the stage to the top instead of the center was the actual fix, and at a narrow 320×200 phone frame it still wasn't enough — the panel title and description lines had to be hidden there too, leaving only the bold item names. The sortable table's first version highlighted each row's background in sequence, but measuring it showed almost no frame-to-frame change — it read as "not moving" even though something clearly cycled on screen. Pieces that only count upward on their own are gathered in Weather Widget Design. Swapping that for one highlight band that actually translates down the table fixed it — open the zip with password rzae7dqh and check the current build, and the table now moves as clearly as the other eight. The donut chart started as two SVG arcs, but their start angles kept drifting out of sync by a few degrees; switching to conic-gradient plus a registered @property made a single value change animate cleanly instead.

Accessibility

What we checked

All nine turn off their looping decorative motion under prefers-reduced-motion: reduce — the sidebar's auto-collapse loop, the sparkline auto-draw, the filter chips auto-press, the bell and avatar pulse — while keeping the real state as-is. The notifications panel (08) and user menu (09) both use role="menu"/role="menuitem" and close on an outside click; only the user menu also closes on Escape. The settings toggle (07) exposes role="switch" with aria-checked and responds only to Enter and Space. The sortable table (03) announces its current order through aria-sort, and the empty state (06) actually toggles aria-hidden on the swapped-in card so a screen reader doesn't read a card that isn't visible. This follows MDN's ARIA widget roles reference.

Where to go next

More dashboard-adjacent pieces live in the template category, and what this site does overall is on the about page.

FAQ

Can I use just one of these dashboard design examples instead of a full template?

Yes — that's the whole point of this set. Each demo already shows one widget alone on the frame, not a full page, and the zip ships that same single widget's HTML, SCSS, and JS so you can move it straight into your own sidebar or header. The kind that walks a first-time visitor across the screen instead is covered in Onboarding UI Design.

Does the React version behave differently from the CSS version?

The behavior is the same. Open/closed and selection state live in useState, and the three variables (duration, easing, color) come in as props mapped to CSS custom properties. The donut counter's count-up runs the same math inside useEffect with requestAnimationFrame.

Is the notification badge or sidebar collapse actually functional, or just decoration?

They're functional. Clicking a notification really flips its unread state and the badge recount reflects what's left; the sidebar toggle really changes the width value. The looping motion you see in the auto-playing GIF is a decorative loop that only runs before anyone interacts — it stops the instant you click or tap.

Enter the archive password

The password is inside this article. You will find it as you read.