Dashboard Skeleton
Sixteen synchronised shimmer bones — 3 KPI cards, an 80 px chart area, 3 table rows — pure CSS, 1.8 s, zero JavaScript.
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



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-motionnot handled: theshimmerSlideanimation runs continuously regardless of the system preference (measured under Playwrightreducecontext:animationName “shimmerSlide”,animationDuration “1.8s”). Add@media (prefers-reduced-motion: reduce) { .skel-bone::after, .skel-bone-circle::after { animation: none; } }— the grey backgroundrgba(255,255,255,.08)stays visible as a static loading placeholder.- No ARIA semantics or accessible label: no
role="status",aria-busy,aria-liveor accessible text in the sold code. For screen readers, wrap.dash-skelin<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 withrgba(0,0,0,.08)in.skel-boneand update the gradient peak in::aftertorgba(0,0,0,.1). - Lifecycle: the 16 empty, silent
divs never modify the accessibility tree after creation. Plan to remove or hide.dash-skelonce 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.
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):
<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>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
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
::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..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.