Loaders✨ Premium

Dashboard Skeleton

Sixteen synchronised shimmer bones — 3 KPI cards, an 80 px chart area, 3 table rows — pure CSS, 1.8 s, zero JavaScript.

CSSShimmerDashboard

You'll get access to the interactive demo with a free account.

This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Loaders has 29 effects, including 4 free. Explore the category →

3 usage examples

Infrastructure monitoring dashboard — overview screen of a server monitoring app — Dashboard Skeleton example 1

① Infrastructure monitoring dashboard — overview screen of a server monitoring app

WhenWhen opening or refreshing the “Overview” tab of a server-monitoring tool (CPU, memory, requests per second) before the real-time metrics return from the server.
WhyThe composite layout — 3 KPIs + chart area + table — faithfully mirrors the target page structure: the user recognises the zone being prepared without reading any text. A spinner would not convey the density of incoming content; a generic line skeleton would not prime the eye for the same layout.
SettingsSet .dash-skel-chart { height: 120px } for a taller real-time chart; align .dash-skel-cell1/2/3 with the actual column widths of the target table for a seamless transition.
Control-room wall screen — boards rotate on their own, each switch leaves a second of skeleton — Dashboard Skeleton example 2

② Control-room wall screen — boards rotate on their own, each switch leaves a second of skeleton

WhenOn the wall of a network operations centre, a screen with no keyboard or mouse cycles through six boards automatically, one every 20 s; at each switch, the next board’s metrics take about a second to arrive.
WhyNobody interacts with this screen: the only sign that the rotation has moved on is what fills that one second. A spinner or a progress bar would be a dot from five metres away; here the skeleton fills the whole frame and draws, in advance, the exact silhouette of the incoming board — three counters, a curve, rows — so an operator at the back of the room knows the rotation advanced and reads the structure before the first figure lands. The 16 bones swept in phase (animation-delay: 0s on every ::after) form a single streak crossing the screen, legible at distance where a cascade or a per-tile indicator would be lost.
Settings.dash-skel { width: 100% } to span the screen width (504 px here, versus 310 by default). Shorten the animation from 1.8s to 1s: with ease-in-out and a 200 % gradient, the streak’s peak only enters the bones at 0.90 s of a 1.8 s cycle and leaves at 1.18 s — during the one-second switch it never finishes crossing them; at 1 s it crosses between 0.50 and 0.65 s. Raise the gradient peak from rgba(255,255,255,.1) to .18 so the streak stays visible at distance; keep the 80 px chart height and the 30 / 45 / 20 % columns.
Weekly SaaS report — summary panel shown on login — Dashboard Skeleton example 3

③ Weekly SaaS report — summary panel shown on login

WhenOn login to an email marketing tool, before the week’s metrics (clicks, open rate, conversions) return from the server.
WhyThe user knows a report is being prepared. The dashboard structure — figures, chart, rows — tells them what they are about to see, lowering waiting anxiety. A generic loader would not say “there is a data table here”.
SettingsNo changes needed for waits under 3 s. For longer loads, add animation-delay: .15s to the second card’s .skel-bone::after and .3s to the third for a gentle cascade.

How it works

The .dash-skel container measures 310 × 222 px (measured), padding 14 px, background rgba(255,255,255,.02), border at 5 % opacity. It holds three stacked zones. First: 3 stat cards in a 3-column CSS grid (grid-template-columns: 1fr 1fr 1fr, gap 8 px) — each card contains two bones, a label 8 px tall (60 % of the card, 41 px measured) and a value 18 px tall (50 %, 34 px measured). Second: a chart-area bone (.dash-skel-chart, 280 × 80 px measured, 100 % of the container’s inner width). Third: 3 table rows of 3 cells each; the first row uses the default CSS widths (30 % / 45 % / 20 %), the next two override widths inline (25 % and 35 % on the first column), simulating variable-length data. Total count: 16 .skel-bone, all present in the sold HTML, none created by script.

The shimmer is entirely CSS. Each .skel-bone carries a ::after pseudo-element positioned with inset: 0 to fill the bone exactly. That pseudo-element’s background is a horizontal linear gradient: transparent → rgba(255,255,255,.1) at the 50 % peak → transparent, sized at 200% 100% — twice the bone’s width. @keyframes shimmerSlide animates background-position from -200% 0 to 200% 0: the gradient, twice as wide as the bone, travels a 400 % range per cycle. The light streak (10 % opacity at the peak) sweeps through the bone once per cycle, from off-screen left to off-screen right. The animation is declared explicitly: 1.8s ease-in-out 0s infinite normal none running shimmerSlide. No delay (animation-delay: 0s): all 16 glows sweep in phase, like a single field washing across the interface.

No JavaScript. The CSS uses no var(--…) custom properties from the site’s design system — no external dependency, no transparent value from a missing declaration. The sold HTML includes .demo-preview, the site’s centering wrapper (display: flex ; min-height: 300px ; background: #0a0a0f), which is not required: .dash-skel integrates directly into any layout. The .skel-bone-circle class is defined in the CSS (border-radius 50 %) but absent from the sold HTML — available should the buyer wish to add a round avatar bone.

Accessibility

  • prefers-reduced-motion not handled: the shimmerSlide animation runs continuously regardless of the system preference (measured under Playwright reduce context: animationName “shimmerSlide”, animationDuration “1.8s”). Add @media (prefers-reduced-motion: reduce) { .skel-bone::after, .skel-bone-circle::after { animation: none; } } — the grey background rgba(255,255,255,.08) stays visible as a static loading placeholder.
  • No ARIA semantics or accessible label: no role="status", aria-busy, aria-live or accessible text in the sold code. For screen readers, wrap .dash-skel in <div role="status" aria-label="Loading dashboard…"> and remove the element from the DOM when the real content appears.
  • Bone background on light themes: rgba(255,255,255,.08) on white measures less than 1 % difference — the bars are invisible. On a light theme, replace with rgba(0,0,0,.08) in .skel-bone and update the gradient peak in ::after to rgba(0,0,0,.1).
  • Lifecycle: the 16 empty, silent divs never modify the accessibility tree after creation. Plan to remove or hide .dash-skel once data has loaded — leaving a skeleton visible indefinitely is misleading for assistive technology users.

Browser compatibility

Pure CSS: @keyframes, ::after pseudo-elements, animation, CSS Grid, inset. The inset property is the most recent (Chrome 87, Firefox 87, Safari 14.1, Edge 87). Zero dependencies.

Chrome 87+✓ Full
Firefox 87+✓ Full
Safari 14.1+✓ Full
Edge 87+✓ Full
Mobile iOS 14.5+✓ Full
Android Chrome 87+✓ Full

Replace inset: 0 with top:0;right:0;bottom:0;left:0 in .skel-bone::after to reach Chrome 57 / Firefox 52 / Safari 10.1 (bottleneck: CSS Grid). Without CSS Grid (IE), the 3 stat cards stack vertically instead of lining up in columns.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
<div class="dash-skel">
  <div class="dash-skel-stats">
    <div class="dash-skel-stat-card">
      <div class="skel-bone dash-skel-stat-label"></div>
      <div class="skel-bone dash-skel-stat-val"></div>
    </div>
    <!-- … 2 more identical cards -->
  </div>
  <div class="skel-bone dash-skel-chart"></div>
  <div class="dash-skel-table">
    <div class="dash-skel-row">
      <div class="skel-bone dash-skel-cell1"></div>
      <div class="skel-bone dash-skel-cell2"></div>
      <div class="skel-bone dash-skel-cell3"></div>
    </div>
    <!-- … 2 more rows (variable widths via style="width:…") -->
  </div>
</div>
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Stat card count — HTML: 3 .dash-skel-stat-card 3 Remove or duplicate a .dash-skel-stat-card; update grid-template-columns to match (e.g. 1fr 1fr for 2 cards, repeat(4, 1fr) for 4).
Chart area height — CSS: .dash-skel-chart { height: 80px } 80 px Raise to 120px for a taller real-time chart, lower to 40px for a sparkline, or remove the element entirely if the interface has no chart.
Column widths — CSS: .dash-skel-cell1 30 %, .dash-skel-cell2 45 %, .dash-skel-cell3 20 % 30 % / 45 % / 20 % Align these percentages with the actual columns of the target table; the default widths and the inline style="width:…" overrides on rows 2 and 3 already simulate length variability.
Table row count — HTML: 3 .dash-skel-row 3 Add or remove .dash-skel-row elements inside .dash-skel-table; each row holds 3 cells. Override individual cell widths with inline style="width:…" to vary each row.
Shimmer duration — CSS: animation: 1.8s ease-in-out 0s infinite… 1.8 s 1s for a fast load, 3s for heavy content; change the first value in the animation declaration on .skel-bone::after.
Shimmer intensity — CSS: rgba(255,255,255,.1) at the gradient peak .1 (10 % opacity) Raise to .18 for a stronger gleam; lower to .06 for a very subtle effect. On a light theme, replace with rgba(0,0,0,.1) together with the bone background.
Bone background — CSS: .skel-bone { background: rgba(255,255,255,.08) } rgba(255,255,255,.08) Grey base of the bars; on a light theme, replace with rgba(0,0,0,.08). The .skel-bone-circle class is defined in the CSS (border-radius 50 %) but absent from the HTML — add it to an empty div to get a round avatar bone.

FAQ

Card Skeleton simulates a single product card — round avatar, image, title, text lines — and has 7 bones. Dashboard Skeleton covers three structurally distinct zones (numeric KPIs, chart area, tabular data) in 16 bones. Card Skeleton bones are sized for a list cell or content card; Dashboard Skeleton bones are proportioned for a reporting interface where the eye scans top to bottom across zones, not item by item.
Yes. All ::after pseudo-elements carry animation-delay: 0s: the 16 glows sweep in phase. This is standard for a dashboard skeleton — the read is global. For a cascade effect (cards lighting up one after another), add incremental delays: .dash-skel-stat-card:nth-child(2) .skel-bone::after { animation-delay: .15s } and :nth-child(3) at .3s.
Hide or remove .dash-skel from the DOM and render the real content in its place. For a smooth transition: dashSkel.style.transition = 'opacity .3s' ; dashSkel.style.opacity = '0', then remove the element on transitionend. The sold code installs no event listeners — there is nothing to clean up on the JavaScript side.