Revenue, 30 days
+12.4%
$48.2k
A dashboard stat card whose sparkline draws itself in the accent over a faint copy, then fills its area and pops an end dot. pathLength 100 makes the stroke-dashoffset draw size-proof.
Also known as: kpi card hover, dashboard stat card css, sparkline draw animation.
<article class="hfx-card-stat-sparkline">
<div class="hfx-card-stat-sparkline-head">
<span>Revenue, 30 days</span>
<span class="hfx-card-stat-sparkline-delta">+12.4%</span>
</div>
<strong>$48.2k</strong>
<svg class="hfx-card-stat-sparkline-chart" viewBox="0 0 124 40" aria-hidden="true">
<path class="hfx-card-stat-sparkline-area" d="M3 33 16 28l13 3 13-10 13 4 13-9 13 3 13-9 13 1 11-4V40H3z"/>
<path class="hfx-card-stat-sparkline-base" d="M3 33 16 28l13 3 13-10 13 4 13-9 13 3 13-9 13 1 11-4" pathLength="100"/>
<path class="hfx-card-stat-sparkline-line" d="M3 33 16 28l13 3 13-10 13 4 13-9 13 3 13-9 13 1 11-4" pathLength="100"/>
<circle class="hfx-card-stat-sparkline-dot" cx="118" cy="7" r="3.2"/>
</svg>
</article>.hfx-card-stat-sparkline {
--c: var(--hfx-color, #3b82f6);
font-size: var(--hfx-size, 16px);
width: 15em;
border-radius: 0.75em;
overflow: hidden;
background: #fff;
border: 1px solid color-mix(in srgb, #000 10%, transparent);
color: #1f2937;
font-family: system-ui, sans-serif;
box-sizing: border-box;
width: 13em;
padding: 1em 1.1em 0.9em;
transition: box-shadow 0.35s ease;}
.hfx-card-stat-sparkline:hover { box-shadow: 0 0.8em 1.4em -0.9em color-mix(in srgb, #000 30%, transparent); }
.hfx-card-stat-sparkline-head {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 0.72em;
color: #6b7280;
}
.hfx-card-stat-sparkline-delta {
padding: 0.2em 0.55em;
border-radius: 99em;
background: color-mix(in srgb, var(--c) 12%, transparent);
color: var(--c);
font-weight: 700;
transition: background-color 0.3s ease, color 0.3s ease;
}
.hfx-card-stat-sparkline:hover .hfx-card-stat-sparkline-delta {
background: var(--c);
color: #fff;
}
.hfx-card-stat-sparkline strong {
display: block;
margin: 0.2em 0 0.35em;
font-size: 1.75em;
font-weight: 700;
letter-spacing: -0.02em;
color: #111827;
transform-origin: 0 50%;
transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1), color 0.3s ease;
}
.hfx-card-stat-sparkline:hover strong {
color: var(--c);
transform: scale(1.06);
}
.hfx-card-stat-sparkline-chart {
display: block;
width: 100%;
height: auto;
overflow: visible;
}
.hfx-card-stat-sparkline-chart path:not(.hfx-card-stat-sparkline-area) {
fill: none;
stroke-width: 2.4;
stroke-linecap: round;
stroke-linejoin: round;
}
.hfx-card-stat-sparkline-base { stroke: color-mix(in srgb, #000 12%, transparent); }
.hfx-card-stat-sparkline-line {
stroke: var(--c);
stroke-dasharray: 100;
stroke-dashoffset: 100;
transition: stroke-dashoffset 0.9s cubic-bezier(0.65, 0, 0.35, 1);
}
.hfx-card-stat-sparkline:hover .hfx-card-stat-sparkline-line { stroke-dashoffset: 0; }
.hfx-card-stat-sparkline-area {
fill: color-mix(in srgb, var(--c) 14%, transparent);
opacity: 0;
transition: opacity 0.4s ease;
}
.hfx-card-stat-sparkline:hover .hfx-card-stat-sparkline-area {
opacity: 1;
transition-delay: 0.5s;
}
.hfx-card-stat-sparkline-dot {
fill: var(--c);
stroke: #fff;
stroke-width: 1.5;
transform: scale(0);
transform-box: fill-box;
transform-origin: center;
transition: transform 0.35s cubic-bezier(0.34, 1.8, 0.64, 1);
}
.hfx-card-stat-sparkline:hover .hfx-card-stat-sparkline-dot {
transform: scale(1);
transition-delay: 0.8s;
}
@media (prefers-reduced-motion: reduce) {
.hfx-card-stat-sparkline, .hfx-card-stat-sparkline *, .hfx-card-stat-sparkline::before, .hfx-card-stat-sparkline::after, .hfx-card-stat-sparkline *::before, .hfx-card-stat-sparkline *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--hfx-color on the element or a parent.
Currently previewing #3b82f6.--hfx-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 16px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.