12 CSS Steppers05 / 12
CSS Animated Step Indicator With Icons
Icon bubble steps with a checkmark overlay pop animation, an SVG arc ring that advances its stroke-dashoffset per step, and a teal/emerald colour scheme — designed for onboarding and setup flows.
Published
This is a full-page demo — interact inside the frame above, or open it in the playground for the full-screen experience.
The code
<div class="stp-05">
<div class="stp-05__wrap">
<div class="stp-05__label">Onboarding Flow</div>
<div class="stp-05__title">Set Up Your Workspace</div>
<div class="stp-05__stepper" id="stp-05-stepper">
<div class="stp-05__item is-done" data-i="1">
<div class="stp-05__bubble">🎨<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Theme</span>
<span class="stp-05__sub">Appearance</span>
</div>
<div class="stp-05__item is-done" data-i="2">
<div class="stp-05__bubble">👥<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Team</span>
<span class="stp-05__sub">Invite members</span>
</div>
<div class="stp-05__item active" data-i="3">
<div class="stp-05__bubble">🔗<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Integrations</span>
<span class="stp-05__sub">Connect apps</span>
</div>
<div class="stp-05__item" data-i="4">
<div class="stp-05__bubble">📊<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Analytics</span>
<span class="stp-05__sub">Set up tracking</span>
</div>
<div class="stp-05__item" data-i="5">
<div class="stp-05__bubble">🚀<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Launch</span>
<span class="stp-05__sub">Go live</span>
</div>
</div>
<div class="stp-05__panel">
<div class="stp-05__panel-inner" data-panel="1">
<div class="stp-05__panel-title">Choose Your Theme</div>
<div class="stp-05__panel-desc">Personalise your workspace with colours and typography that match your brand.</div>
<div class="stp-05__tags"><span class="stp-05__tag">Dark Mode</span><span class="stp-05__tag">Custom Palette</span><span class="stp-05__tag">Font Scale</span></div>
</div>
<div class="stp-05__panel-inner" data-panel="2">
<div class="stp-05__panel-title">Invite Your Team</div>
<div class="stp-05__panel-desc">Add teammates by email. Assign roles and set permissions for each member.</div>
<div class="stp-05__tags"><span class="stp-05__tag">Admin</span><span class="stp-05__tag">Editor</span><span class="stp-05__tag">Viewer</span></div>
</div>
<div class="stp-05__panel-inner active" data-panel="3">
<div class="stp-05__panel-title">Connect Integrations</div>
<div class="stp-05__panel-desc">Link your favourite tools — Slack, GitHub, Figma, Linear and more — to keep everything in sync.</div>
<div class="stp-05__tags"><span class="stp-05__tag">Slack</span><span class="stp-05__tag">GitHub</span><span class="stp-05__tag">Figma</span><span class="stp-05__tag">Linear</span><span class="stp-05__tag">Notion</span></div>
<div class="stp-05__progress">
<svg class="stp-05__ring" viewBox="0 0 44 44">
<circle class="bg" cx="22" cy="22" r="20"/>
<circle class="fg" id="stp-05-ring" cx="22" cy="22" r="20"/>
</svg>
<div>
<div class="stp-05__pct" id="stp-05-pct">40%</div>
<div class="stp-05__pct-label">Overall Progress</div>
</div>
</div>
</div>
<div class="stp-05__panel-inner" data-panel="4">
<div class="stp-05__panel-title">Configure Analytics</div>
<div class="stp-05__panel-desc">Set up event tracking, conversion goals, and dashboard widgets to stay on top of performance.</div>
<div class="stp-05__tags"><span class="stp-05__tag">Events</span><span class="stp-05__tag">Goals</span><span class="stp-05__tag">Funnels</span></div>
</div>
<div class="stp-05__panel-inner" data-panel="5">
<div class="stp-05__panel-title">🚀 Ready to Launch!</div>
<div class="stp-05__panel-desc">Your workspace is fully configured. Click Launch to go live and start collaborating with your team.</div>
<div class="stp-05__tags"><span class="stp-05__tag">All systems go</span><span class="stp-05__tag">5 steps complete</span></div>
</div>
<div class="stp-05__nav">
<button class="stp-05__btn stp-05__btn--prev" id="stp-05-prev">← Previous</button>
<button class="stp-05__btn stp-05__btn--next" id="stp-05-next">Continue →</button>
</div>
</div>
</div>
</div><div class="stp-05">
<div class="stp-05__wrap">
<div class="stp-05__label">Onboarding Flow</div>
<div class="stp-05__title">Set Up Your Workspace</div>
<div class="stp-05__stepper" id="stp-05-stepper">
<div class="stp-05__item is-done" data-i="1">
<div class="stp-05__bubble">🎨<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Theme</span>
<span class="stp-05__sub">Appearance</span>
</div>
<div class="stp-05__item is-done" data-i="2">
<div class="stp-05__bubble">👥<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Team</span>
<span class="stp-05__sub">Invite members</span>
</div>
<div class="stp-05__item active" data-i="3">
<div class="stp-05__bubble">🔗<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Integrations</span>
<span class="stp-05__sub">Connect apps</span>
</div>
<div class="stp-05__item" data-i="4">
<div class="stp-05__bubble">📊<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Analytics</span>
<span class="stp-05__sub">Set up tracking</span>
</div>
<div class="stp-05__item" data-i="5">
<div class="stp-05__bubble">🚀<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Launch</span>
<span class="stp-05__sub">Go live</span>
</div>
</div>
<div class="stp-05__panel">
<div class="stp-05__panel-inner" data-panel="1">
<div class="stp-05__panel-title">Choose Your Theme</div>
<div class="stp-05__panel-desc">Personalise your workspace with colours and typography that match your brand.</div>
<div class="stp-05__tags"><span class="stp-05__tag">Dark Mode</span><span class="stp-05__tag">Custom Palette</span><span class="stp-05__tag">Font Scale</span></div>
</div>
<div class="stp-05__panel-inner" data-panel="2">
<div class="stp-05__panel-title">Invite Your Team</div>
<div class="stp-05__panel-desc">Add teammates by email. Assign roles and set permissions for each member.</div>
<div class="stp-05__tags"><span class="stp-05__tag">Admin</span><span class="stp-05__tag">Editor</span><span class="stp-05__tag">Viewer</span></div>
</div>
<div class="stp-05__panel-inner active" data-panel="3">
<div class="stp-05__panel-title">Connect Integrations</div>
<div class="stp-05__panel-desc">Link your favourite tools — Slack, GitHub, Figma, Linear and more — to keep everything in sync.</div>
<div class="stp-05__tags"><span class="stp-05__tag">Slack</span><span class="stp-05__tag">GitHub</span><span class="stp-05__tag">Figma</span><span class="stp-05__tag">Linear</span><span class="stp-05__tag">Notion</span></div>
<div class="stp-05__progress">
<svg class="stp-05__ring" viewBox="0 0 44 44">
<circle class="bg" cx="22" cy="22" r="20"/>
<circle class="fg" id="stp-05-ring" cx="22" cy="22" r="20"/>
</svg>
<div>
<div class="stp-05__pct" id="stp-05-pct">40%</div>
<div class="stp-05__pct-label">Overall Progress</div>
</div>
</div>
</div>
<div class="stp-05__panel-inner" data-panel="4">
<div class="stp-05__panel-title">Configure Analytics</div>
<div class="stp-05__panel-desc">Set up event tracking, conversion goals, and dashboard widgets to stay on top of performance.</div>
<div class="stp-05__tags"><span class="stp-05__tag">Events</span><span class="stp-05__tag">Goals</span><span class="stp-05__tag">Funnels</span></div>
</div>
<div class="stp-05__panel-inner" data-panel="5">
<div class="stp-05__panel-title">🚀 Ready to Launch!</div>
<div class="stp-05__panel-desc">Your workspace is fully configured. Click Launch to go live and start collaborating with your team.</div>
<div class="stp-05__tags"><span class="stp-05__tag">All systems go</span><span class="stp-05__tag">5 steps complete</span></div>
</div>
<div class="stp-05__nav">
<button class="stp-05__btn stp-05__btn--prev" id="stp-05-prev">← Previous</button>
<button class="stp-05__btn stp-05__btn--next" id="stp-05-next">Continue →</button>
</div>
</div>
</div>
</div>.stp-05,
.stp-05 *,
.stp-05 *::before,
.stp-05 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.stp-05 ::selection {
background: #059669;
color: #fff;
}
.stp-05 {
--bg: #041a14;
--card: #071f18;
--emerald: #10b981;
--teal: #14b8a6;
--lime: #84cc16;
--dark: #d1fae5;
--muted: #2d6a54;
--border: #0d3d2e;
--white: #ecfdf5;
font-family: 'Segoe UI',system-ui,sans-serif;
background: var(--bg);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 40px 20px;
background-image: radial-gradient(ellipse at 30% 60%,rgba(16,185,129,.08) 0%,transparent 55%), radial-gradient(ellipse at 80% 20%,rgba(20,184,166,.06) 0%,transparent 40%);
}
.stp-05__wrap {
max-width: 700px;
width: 100%;
}
.stp-05__label {
font-size: 10px;
letter-spacing: .16em;
text-transform: uppercase;
color: var(--emerald);
font-weight: 700;
text-align: center;
margin-bottom: 12px;
}
.stp-05__title {
font-size: 26px;
font-weight: 800;
color: var(--white);
text-align: center;
letter-spacing: -.02em;
margin-bottom: 40px;
}
/* stepper */
.stp-05__stepper {
display: flex;
align-items: flex-start;
gap: 0;
margin-bottom: 48px;
}
.stp-05__item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
position: relative;
}
/* connector */
.stp-05__item:not(:last-child)::after {
content: '';
position: absolute;
top: 32px;
left: calc(50% + 32px);
width: calc(100% - 64px);
height: 2px;
background: var(--border);
transition: background .5s ease;
}
.stp-05__item.done::after {
background: linear-gradient(90deg,var(--emerald),var(--teal));
animation: stp-05-flash .4s ease;
}
@keyframes stp-05-flash {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
/* icon bubble */
.stp-05__bubble {
width: 64px;
height: 64px;
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 26px;
background: var(--border);
border: 2px solid var(--muted);
transition: all .4s cubic-bezier(.34,1.56,.64,1);
position: relative;
overflow: hidden;
}
.stp-05__bubble::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg,rgba(255,255,255,.05),transparent);
opacity: 0;
transition: opacity .3s;
}
.stp-05__item.done .stp-05__bubble {
background: linear-gradient(135deg,rgba(16,185,129,.25),rgba(20,184,166,.15));
border-color: var(--emerald);
box-shadow: 0 0 24px rgba(16,185,129,.3),inset 0 1px 0 rgba(255,255,255,.1);
}
.stp-05__item.done .stp-05__bubble::before {
opacity: 1;
}
.stp-05__item.active .stp-05__bubble {
background: linear-gradient(135deg,rgba(16,185,129,.15),rgba(132,204,22,.1));
border-color: var(--teal);
box-shadow: 0 0 0 6px rgba(16,185,129,.1),0 0 32px rgba(16,185,129,.3);
animation: stp-05-bob 2.5s ease-in-out infinite;
}
@keyframes stp-05-bob {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-4px);
}
}
/* checkmark overlay */
.stp-05__check {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 22px;
background: linear-gradient(135deg,var(--emerald),var(--teal));
border-radius: 18px;
opacity: 0;
transform: scale(.5);
transition: all .3s cubic-bezier(.34,1.56,.64,1);
}
.stp-05__item.done .stp-05__check {
opacity: 1;
transform: scale(1);
}
.stp-05__name {
font-size: 12px;
font-weight: 600;
color: var(--muted);
text-align: center;
letter-spacing: .04em;
text-transform: uppercase;
transition: color .3s;
}
.stp-05__item.done .stp-05__name {
color: var(--emerald);
}
.stp-05__item.active .stp-05__name {
color: var(--white);
}
.stp-05__sub {
font-size: 11px;
color: var(--border);
text-align: center;
transition: color .3s;
}
.stp-05__item.active .stp-05__sub {
color: var(--muted);
}
.stp-05__item.done .stp-05__sub {
color: var(--muted);
}
/* content panel */
.stp-05__panel {
background: var(--card);
border: 1px solid var(--border);
border-radius: 18px;
padding: 28px 32px;
min-height: 200px;
position: relative;
overflow: hidden;
}
.stp-05__panel::before {
content: '';
position: absolute;
top: -60px;
right: -60px;
width: 180px;
height: 180px;
border-radius: 50%;
background: radial-gradient(circle,rgba(16,185,129,.08),transparent);
}
.stp-05__panel-inner {
display: none;
}
.stp-05__panel-inner.active {
display: block;
animation: stp-05-in .35s ease;
}
@keyframes stp-05-in {
from {
opacity: 0;
transform: translateX(10px);
}
to {
opacity: 1;
transform: none;
}
}
.stp-05__panel-title {
font-size: 18px;
font-weight: 700;
color: var(--white);
margin-bottom: 8px;
}
.stp-05__panel-desc {
font-size: 14px;
color: var(--muted);
line-height: 1.7;
margin-bottom: 20px;
}
.stp-05__tags {
display: flex;
gap: 8px;
flex-wrap: wrap;
margin-bottom: 20px;
}
.stp-05__tag {
padding: 4px 12px;
border-radius: 999px;
font-size: 11px;
font-weight: 600;
background: rgba(16,185,129,.12);
border: 1px solid rgba(16,185,129,.25);
color: var(--emerald);
}
.stp-05__nav {
display: flex;
justify-content: space-between;
margin-top: 24px;
}
.stp-05__btn {
padding: 10px 24px;
border-radius: 10px;
border: none;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: all .2s;
}
.stp-05__btn--prev {
background: var(--border);
color: var(--muted);
}
.stp-05__btn--prev:hover {
color: var(--white);
}
.stp-05__btn--next {
background: linear-gradient(135deg,var(--emerald),var(--teal));
color: #fff;
box-shadow: 0 4px 16px rgba(16,185,129,.3);
}
.stp-05__btn--next:hover {
transform: translateY(-1px);
box-shadow: 0 8px 24px rgba(16,185,129,.4);
}
/* progress ring */
.stp-05__progress {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
margin-bottom: 20px;
}
.stp-05__ring {
width: 52px;
height: 52px;
}
.stp-05__ring circle {
fill: none;
stroke-width: 4;
stroke-linecap: round;
}
.stp-05__ring .bg {
stroke: var(--border);
}
.stp-05__ring .fg {
stroke: var(--emerald);
stroke-dasharray: 126;
stroke-dashoffset: 126;
transform: rotate(-90deg);
transform-origin: center;
transition: stroke-dashoffset .5s ease;
}
.stp-05__pct {
font-size: 13px;
font-weight: 700;
color: var(--emerald);
}
.stp-05__pct-label {
font-size: 12px;
color: var(--muted);
}
@media (prefers-reduced-motion: reduce) {
.stp-05__item.active .stp-05__bubble {
animation: none;
}
.stp-05__item.done::after,
.stp-05__panel-inner.active {
animation: none;
}
}.stp-05,
.stp-05 *,
.stp-05 *::before,
.stp-05 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.stp-05 ::selection {
background: #059669;
color: #fff;
}
.stp-05 {
--bg: #041a14;
--card: #071f18;
--emerald: #10b981;
--teal: #14b8a6;
--lime: #84cc16;
--dark: #d1fae5;
--muted: #2d6a54;
--border: #0d3d2e;
--white: #ecfdf5;
font-family: 'Segoe UI',system-ui,sans-serif;
background: var(--bg);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 40px 20px;
background-image: radial-gradient(ellipse at 30% 60%,rgba(16,185,129,.08) 0%,transparent 55%), radial-gradient(ellipse at 80% 20%,rgba(20,184,166,.06) 0%,transparent 40%);
}
.stp-05__wrap {
max-width: 700px;
width: 100%;
}
.stp-05__label {
font-size: 10px;
letter-spacing: .16em;
text-transform: uppercase;
color: var(--emerald);
font-weight: 700;
text-align: center;
margin-bottom: 12px;
}
.stp-05__title {
font-size: 26px;
font-weight: 800;
color: var(--white);
text-align: center;
letter-spacing: -.02em;
margin-bottom: 40px;
}
/* stepper */
.stp-05__stepper {
display: flex;
align-items: flex-start;
gap: 0;
margin-bottom: 48px;
}
.stp-05__item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
position: relative;
}
/* connector */
.stp-05__item:not(:last-child)::after {
content: '';
position: absolute;
top: 32px;
left: calc(50% + 32px);
width: calc(100% - 64px);
height: 2px;
background: var(--border);
transition: background .5s ease;
}
.stp-05__item.done::after {
background: linear-gradient(90deg,var(--emerald),var(--teal));
animation: stp-05-flash .4s ease;
}
@keyframes stp-05-flash {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
/* icon bubble */
.stp-05__bubble {
width: 64px;
height: 64px;
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 26px;
background: var(--border);
border: 2px solid var(--muted);
transition: all .4s cubic-bezier(.34,1.56,.64,1);
position: relative;
overflow: hidden;
}
.stp-05__bubble::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg,rgba(255,255,255,.05),transparent);
opacity: 0;
transition: opacity .3s;
}
.stp-05__item.done .stp-05__bubble {
background: linear-gradient(135deg,rgba(16,185,129,.25),rgba(20,184,166,.15));
border-color: var(--emerald);
box-shadow: 0 0 24px rgba(16,185,129,.3),inset 0 1px 0 rgba(255,255,255,.1);
}
.stp-05__item.done .stp-05__bubble::before {
opacity: 1;
}
.stp-05__item.active .stp-05__bubble {
background: linear-gradient(135deg,rgba(16,185,129,.15),rgba(132,204,22,.1));
border-color: var(--teal);
box-shadow: 0 0 0 6px rgba(16,185,129,.1),0 0 32px rgba(16,185,129,.3);
animation: stp-05-bob 2.5s ease-in-out infinite;
}
@keyframes stp-05-bob {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-4px);
}
}
/* checkmark overlay */
.stp-05__check {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 22px;
background: linear-gradient(135deg,var(--emerald),var(--teal));
border-radius: 18px;
opacity: 0;
transform: scale(.5);
transition: all .3s cubic-bezier(.34,1.56,.64,1);
}
.stp-05__item.done .stp-05__check {
opacity: 1;
transform: scale(1);
}
.stp-05__name {
font-size: 12px;
font-weight: 600;
color: var(--muted);
text-align: center;
letter-spacing: .04em;
text-transform: uppercase;
transition: color .3s;
}
.stp-05__item.done .stp-05__name {
color: var(--emerald);
}
.stp-05__item.active .stp-05__name {
color: var(--white);
}
.stp-05__sub {
font-size: 11px;
color: var(--border);
text-align: center;
transition: color .3s;
}
.stp-05__item.active .stp-05__sub {
color: var(--muted);
}
.stp-05__item.done .stp-05__sub {
color: var(--muted);
}
/* content panel */
.stp-05__panel {
background: var(--card);
border: 1px solid var(--border);
border-radius: 18px;
padding: 28px 32px;
min-height: 200px;
position: relative;
overflow: hidden;
}
.stp-05__panel::before {
content: '';
position: absolute;
top: -60px;
right: -60px;
width: 180px;
height: 180px;
border-radius: 50%;
background: radial-gradient(circle,rgba(16,185,129,.08),transparent);
}
.stp-05__panel-inner {
display: none;
}
.stp-05__panel-inner.active {
display: block;
animation: stp-05-in .35s ease;
}
@keyframes stp-05-in {
from {
opacity: 0;
transform: translateX(10px);
}
to {
opacity: 1;
transform: none;
}
}
.stp-05__panel-title {
font-size: 18px;
font-weight: 700;
color: var(--white);
margin-bottom: 8px;
}
.stp-05__panel-desc {
font-size: 14px;
color: var(--muted);
line-height: 1.7;
margin-bottom: 20px;
}
.stp-05__tags {
display: flex;
gap: 8px;
flex-wrap: wrap;
margin-bottom: 20px;
}
.stp-05__tag {
padding: 4px 12px;
border-radius: 999px;
font-size: 11px;
font-weight: 600;
background: rgba(16,185,129,.12);
border: 1px solid rgba(16,185,129,.25);
color: var(--emerald);
}
.stp-05__nav {
display: flex;
justify-content: space-between;
margin-top: 24px;
}
.stp-05__btn {
padding: 10px 24px;
border-radius: 10px;
border: none;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: all .2s;
}
.stp-05__btn--prev {
background: var(--border);
color: var(--muted);
}
.stp-05__btn--prev:hover {
color: var(--white);
}
.stp-05__btn--next {
background: linear-gradient(135deg,var(--emerald),var(--teal));
color: #fff;
box-shadow: 0 4px 16px rgba(16,185,129,.3);
}
.stp-05__btn--next:hover {
transform: translateY(-1px);
box-shadow: 0 8px 24px rgba(16,185,129,.4);
}
/* progress ring */
.stp-05__progress {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
margin-bottom: 20px;
}
.stp-05__ring {
width: 52px;
height: 52px;
}
.stp-05__ring circle {
fill: none;
stroke-width: 4;
stroke-linecap: round;
}
.stp-05__ring .bg {
stroke: var(--border);
}
.stp-05__ring .fg {
stroke: var(--emerald);
stroke-dasharray: 126;
stroke-dashoffset: 126;
transform: rotate(-90deg);
transform-origin: center;
transition: stroke-dashoffset .5s ease;
}
.stp-05__pct {
font-size: 13px;
font-weight: 700;
color: var(--emerald);
}
.stp-05__pct-label {
font-size: 12px;
color: var(--muted);
}
@media (prefers-reduced-motion: reduce) {
.stp-05__item.active .stp-05__bubble {
animation: none;
}
.stp-05__item.done::after,
.stp-05__panel-inner.active {
animation: none;
}
}(function(){
let cur=3;
const items=document.querySelectorAll('.stp-05__item');
const panels=document.querySelectorAll('.stp-05__panel-inner');
const ring=document.getElementById('stp-05-ring');
const pct=document.getElementById('stp-05-pct');
const total=5;
function update(){
items.forEach((item,i)=>{
item.classList.remove('done','active','is-done');
if(i+1<cur) item.classList.add('done');
else if(i+1===cur) item.classList.add('active');
});
panels.forEach(p=>{
p.classList.remove('active');
if(parseInt(p.dataset.panel)===cur) p.classList.add('active');
});
const p=((cur-1)/(total-1)*100).toFixed(0);
const offset=126-(126*(cur-1)/(total-1));
ring.style.strokeDashoffset=offset;
pct.textContent=p+'%';
document.getElementById('stp-05-prev').disabled=cur<=1;
document.getElementById('stp-05-next').textContent=cur===total?'Launch 🚀':'Continue →';
}
document.getElementById('stp-05-prev').addEventListener('click',()=>{cur=Math.max(1,cur-1);update();});
document.getElementById('stp-05-next').addEventListener('click',()=>{cur=Math.min(total,cur+1);update();});
update();
})();(function(){
let cur=3;
const items=document.querySelectorAll('.stp-05__item');
const panels=document.querySelectorAll('.stp-05__panel-inner');
const ring=document.getElementById('stp-05-ring');
const pct=document.getElementById('stp-05-pct');
const total=5;
function update(){
items.forEach((item,i)=>{
item.classList.remove('done','active','is-done');
if(i+1<cur) item.classList.add('done');
else if(i+1===cur) item.classList.add('active');
});
panels.forEach(p=>{
p.classList.remove('active');
if(parseInt(p.dataset.panel)===cur) p.classList.add('active');
});
const p=((cur-1)/(total-1)*100).toFixed(0);
const offset=126-(126*(cur-1)/(total-1));
ring.style.strokeDashoffset=offset;
pct.textContent=p+'%';
document.getElementById('stp-05-prev').disabled=cur<=1;
document.getElementById('stp-05-next').textContent=cur===total?'Launch 🚀':'Continue →';
}
document.getElementById('stp-05-prev').addEventListener('click',()=>{cur=Math.max(1,cur-1);update();});
document.getElementById('stp-05-next').addEventListener('click',()=>{cur=Math.min(total,cur+1);update();});
update();
})();Here's a working CSS Stepper from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS Animated Step Indicator With Icons
Source: https://codefronts.com/components/css-stepper-designs/css-animated-step-indicator-with-icons/
Icon bubble steps with a checkmark overlay pop animation, an SVG arc ring that advances its stroke-dashoffset per step, and a teal/emerald colour scheme — designed for onboarding and setup flows.
## HTML
```html
<div class="stp-05">
<div class="stp-05__wrap">
<div class="stp-05__label">Onboarding Flow</div>
<div class="stp-05__title">Set Up Your Workspace</div>
<div class="stp-05__stepper" id="stp-05-stepper">
<div class="stp-05__item is-done" data-i="1">
<div class="stp-05__bubble">🎨<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Theme</span>
<span class="stp-05__sub">Appearance</span>
</div>
<div class="stp-05__item is-done" data-i="2">
<div class="stp-05__bubble">👥<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Team</span>
<span class="stp-05__sub">Invite members</span>
</div>
<div class="stp-05__item active" data-i="3">
<div class="stp-05__bubble">🔗<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Integrations</span>
<span class="stp-05__sub">Connect apps</span>
</div>
<div class="stp-05__item" data-i="4">
<div class="stp-05__bubble">📊<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Analytics</span>
<span class="stp-05__sub">Set up tracking</span>
</div>
<div class="stp-05__item" data-i="5">
<div class="stp-05__bubble">🚀<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Launch</span>
<span class="stp-05__sub">Go live</span>
</div>
</div>
<div class="stp-05__panel">
<div class="stp-05__panel-inner" data-panel="1">
<div class="stp-05__panel-title">Choose Your Theme</div>
<div class="stp-05__panel-desc">Personalise your workspace with colours and typography that match your brand.</div>
<div class="stp-05__tags"><span class="stp-05__tag">Dark Mode</span><span class="stp-05__tag">Custom Palette</span><span class="stp-05__tag">Font Scale</span></div>
</div>
<div class="stp-05__panel-inner" data-panel="2">
<div class="stp-05__panel-title">Invite Your Team</div>
<div class="stp-05__panel-desc">Add teammates by email. Assign roles and set permissions for each member.</div>
<div class="stp-05__tags"><span class="stp-05__tag">Admin</span><span class="stp-05__tag">Editor</span><span class="stp-05__tag">Viewer</span></div>
</div>
<div class="stp-05__panel-inner active" data-panel="3">
<div class="stp-05__panel-title">Connect Integrations</div>
<div class="stp-05__panel-desc">Link your favourite tools — Slack, GitHub, Figma, Linear and more — to keep everything in sync.</div>
<div class="stp-05__tags"><span class="stp-05__tag">Slack</span><span class="stp-05__tag">GitHub</span><span class="stp-05__tag">Figma</span><span class="stp-05__tag">Linear</span><span class="stp-05__tag">Notion</span></div>
<div class="stp-05__progress">
<svg class="stp-05__ring" viewBox="0 0 44 44">
<circle class="bg" cx="22" cy="22" r="20"/>
<circle class="fg" id="stp-05-ring" cx="22" cy="22" r="20"/>
</svg>
<div>
<div class="stp-05__pct" id="stp-05-pct">40%</div>
<div class="stp-05__pct-label">Overall Progress</div>
</div>
</div>
</div>
<div class="stp-05__panel-inner" data-panel="4">
<div class="stp-05__panel-title">Configure Analytics</div>
<div class="stp-05__panel-desc">Set up event tracking, conversion goals, and dashboard widgets to stay on top of performance.</div>
<div class="stp-05__tags"><span class="stp-05__tag">Events</span><span class="stp-05__tag">Goals</span><span class="stp-05__tag">Funnels</span></div>
</div>
<div class="stp-05__panel-inner" data-panel="5">
<div class="stp-05__panel-title">🚀 Ready to Launch!</div>
<div class="stp-05__panel-desc">Your workspace is fully configured. Click Launch to go live and start collaborating with your team.</div>
<div class="stp-05__tags"><span class="stp-05__tag">All systems go</span><span class="stp-05__tag">5 steps complete</span></div>
</div>
<div class="stp-05__nav">
<button class="stp-05__btn stp-05__btn--prev" id="stp-05-prev">← Previous</button>
<button class="stp-05__btn stp-05__btn--next" id="stp-05-next">Continue →</button>
</div>
</div>
</div>
</div>
```
## CSS
```css
.stp-05,
.stp-05 *,
.stp-05 *::before,
.stp-05 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.stp-05 ::selection {
background: #059669;
color: #fff;
}
.stp-05 {
--bg: #041a14;
--card: #071f18;
--emerald: #10b981;
--teal: #14b8a6;
--lime: #84cc16;
--dark: #d1fae5;
--muted: #2d6a54;
--border: #0d3d2e;
--white: #ecfdf5;
font-family: 'Segoe UI',system-ui,sans-serif;
background: var(--bg);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 40px 20px;
background-image: radial-gradient(ellipse at 30% 60%,rgba(16,185,129,.08) 0%,transparent 55%), radial-gradient(ellipse at 80% 20%,rgba(20,184,166,.06) 0%,transparent 40%);
}
.stp-05__wrap {
max-width: 700px;
width: 100%;
}
.stp-05__label {
font-size: 10px;
letter-spacing: .16em;
text-transform: uppercase;
color: var(--emerald);
font-weight: 700;
text-align: center;
margin-bottom: 12px;
}
.stp-05__title {
font-size: 26px;
font-weight: 800;
color: var(--white);
text-align: center;
letter-spacing: -.02em;
margin-bottom: 40px;
}
/* stepper */
.stp-05__stepper {
display: flex;
align-items: flex-start;
gap: 0;
margin-bottom: 48px;
}
.stp-05__item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
position: relative;
}
/* connector */
.stp-05__item:not(:last-child)::after {
content: '';
position: absolute;
top: 32px;
left: calc(50% + 32px);
width: calc(100% - 64px);
height: 2px;
background: var(--border);
transition: background .5s ease;
}
.stp-05__item.done::after {
background: linear-gradient(90deg,var(--emerald),var(--teal));
animation: stp-05-flash .4s ease;
}
@keyframes stp-05-flash {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
/* icon bubble */
.stp-05__bubble {
width: 64px;
height: 64px;
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 26px;
background: var(--border);
border: 2px solid var(--muted);
transition: all .4s cubic-bezier(.34,1.56,.64,1);
position: relative;
overflow: hidden;
}
.stp-05__bubble::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg,rgba(255,255,255,.05),transparent);
opacity: 0;
transition: opacity .3s;
}
.stp-05__item.done .stp-05__bubble {
background: linear-gradient(135deg,rgba(16,185,129,.25),rgba(20,184,166,.15));
border-color: var(--emerald);
box-shadow: 0 0 24px rgba(16,185,129,.3),inset 0 1px 0 rgba(255,255,255,.1);
}
.stp-05__item.done .stp-05__bubble::before {
opacity: 1;
}
.stp-05__item.active .stp-05__bubble {
background: linear-gradient(135deg,rgba(16,185,129,.15),rgba(132,204,22,.1));
border-color: var(--teal);
box-shadow: 0 0 0 6px rgba(16,185,129,.1),0 0 32px rgba(16,185,129,.3);
animation: stp-05-bob 2.5s ease-in-out infinite;
}
@keyframes stp-05-bob {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-4px);
}
}
/* checkmark overlay */
.stp-05__check {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 22px;
background: linear-gradient(135deg,var(--emerald),var(--teal));
border-radius: 18px;
opacity: 0;
transform: scale(.5);
transition: all .3s cubic-bezier(.34,1.56,.64,1);
}
.stp-05__item.done .stp-05__check {
opacity: 1;
transform: scale(1);
}
.stp-05__name {
font-size: 12px;
font-weight: 600;
color: var(--muted);
text-align: center;
letter-spacing: .04em;
text-transform: uppercase;
transition: color .3s;
}
.stp-05__item.done .stp-05__name {
color: var(--emerald);
}
.stp-05__item.active .stp-05__name {
color: var(--white);
}
.stp-05__sub {
font-size: 11px;
color: var(--border);
text-align: center;
transition: color .3s;
}
.stp-05__item.active .stp-05__sub {
color: var(--muted);
}
.stp-05__item.done .stp-05__sub {
color: var(--muted);
}
/* content panel */
.stp-05__panel {
background: var(--card);
border: 1px solid var(--border);
border-radius: 18px;
padding: 28px 32px;
min-height: 200px;
position: relative;
overflow: hidden;
}
.stp-05__panel::before {
content: '';
position: absolute;
top: -60px;
right: -60px;
width: 180px;
height: 180px;
border-radius: 50%;
background: radial-gradient(circle,rgba(16,185,129,.08),transparent);
}
.stp-05__panel-inner {
display: none;
}
.stp-05__panel-inner.active {
display: block;
animation: stp-05-in .35s ease;
}
@keyframes stp-05-in {
from {
opacity: 0;
transform: translateX(10px);
}
to {
opacity: 1;
transform: none;
}
}
.stp-05__panel-title {
font-size: 18px;
font-weight: 700;
color: var(--white);
margin-bottom: 8px;
}
.stp-05__panel-desc {
font-size: 14px;
color: var(--muted);
line-height: 1.7;
margin-bottom: 20px;
}
.stp-05__tags {
display: flex;
gap: 8px;
flex-wrap: wrap;
margin-bottom: 20px;
}
.stp-05__tag {
padding: 4px 12px;
border-radius: 999px;
font-size: 11px;
font-weight: 600;
background: rgba(16,185,129,.12);
border: 1px solid rgba(16,185,129,.25);
color: var(--emerald);
}
.stp-05__nav {
display: flex;
justify-content: space-between;
margin-top: 24px;
}
.stp-05__btn {
padding: 10px 24px;
border-radius: 10px;
border: none;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: all .2s;
}
.stp-05__btn--prev {
background: var(--border);
color: var(--muted);
}
.stp-05__btn--prev:hover {
color: var(--white);
}
.stp-05__btn--next {
background: linear-gradient(135deg,var(--emerald),var(--teal));
color: #fff;
box-shadow: 0 4px 16px rgba(16,185,129,.3);
}
.stp-05__btn--next:hover {
transform: translateY(-1px);
box-shadow: 0 8px 24px rgba(16,185,129,.4);
}
/* progress ring */
.stp-05__progress {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
margin-bottom: 20px;
}
.stp-05__ring {
width: 52px;
height: 52px;
}
.stp-05__ring circle {
fill: none;
stroke-width: 4;
stroke-linecap: round;
}
.stp-05__ring .bg {
stroke: var(--border);
}
.stp-05__ring .fg {
stroke: var(--emerald);
stroke-dasharray: 126;
stroke-dashoffset: 126;
transform: rotate(-90deg);
transform-origin: center;
transition: stroke-dashoffset .5s ease;
}
.stp-05__pct {
font-size: 13px;
font-weight: 700;
color: var(--emerald);
}
.stp-05__pct-label {
font-size: 12px;
color: var(--muted);
}
@media (prefers-reduced-motion: reduce) {
.stp-05__item.active .stp-05__bubble {
animation: none;
}
.stp-05__item.done::after,
.stp-05__panel-inner.active {
animation: none;
}
}
```
## JavaScript
```js
(function(){
let cur=3;
const items=document.querySelectorAll('.stp-05__item');
const panels=document.querySelectorAll('.stp-05__panel-inner');
const ring=document.getElementById('stp-05-ring');
const pct=document.getElementById('stp-05-pct');
const total=5;
function update(){
items.forEach((item,i)=>{
item.classList.remove('done','active','is-done');
if(i+1<cur) item.classList.add('done');
else if(i+1===cur) item.classList.add('active');
});
panels.forEach(p=>{
p.classList.remove('active');
if(parseInt(p.dataset.panel)===cur) p.classList.add('active');
});
const p=((cur-1)/(total-1)*100).toFixed(0);
const offset=126-(126*(cur-1)/(total-1));
ring.style.strokeDashoffset=offset;
pct.textContent=p+'%';
document.getElementById('stp-05-prev').disabled=cur<=1;
document.getElementById('stp-05-next').textContent=cur===total?'Launch 🚀':'Continue →';
}
document.getElementById('stp-05-prev').addEventListener('click',()=>{cur=Math.max(1,cur-1);update();});
document.getElementById('stp-05-next').addEventListener('click',()=>{cur=Math.min(total,cur+1);update();});
update();
})();
```Here's a working CSS Stepper from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS Animated Step Indicator With Icons
Source: https://codefronts.com/components/css-stepper-designs/css-animated-step-indicator-with-icons/
Icon bubble steps with a checkmark overlay pop animation, an SVG arc ring that advances its stroke-dashoffset per step, and a teal/emerald colour scheme — designed for onboarding and setup flows.
## HTML
```html
<div class="stp-05">
<div class="stp-05__wrap">
<div class="stp-05__label">Onboarding Flow</div>
<div class="stp-05__title">Set Up Your Workspace</div>
<div class="stp-05__stepper" id="stp-05-stepper">
<div class="stp-05__item is-done" data-i="1">
<div class="stp-05__bubble">🎨<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Theme</span>
<span class="stp-05__sub">Appearance</span>
</div>
<div class="stp-05__item is-done" data-i="2">
<div class="stp-05__bubble">👥<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Team</span>
<span class="stp-05__sub">Invite members</span>
</div>
<div class="stp-05__item active" data-i="3">
<div class="stp-05__bubble">🔗<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Integrations</span>
<span class="stp-05__sub">Connect apps</span>
</div>
<div class="stp-05__item" data-i="4">
<div class="stp-05__bubble">📊<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Analytics</span>
<span class="stp-05__sub">Set up tracking</span>
</div>
<div class="stp-05__item" data-i="5">
<div class="stp-05__bubble">🚀<div class="stp-05__check">✓</div></div>
<span class="stp-05__name">Launch</span>
<span class="stp-05__sub">Go live</span>
</div>
</div>
<div class="stp-05__panel">
<div class="stp-05__panel-inner" data-panel="1">
<div class="stp-05__panel-title">Choose Your Theme</div>
<div class="stp-05__panel-desc">Personalise your workspace with colours and typography that match your brand.</div>
<div class="stp-05__tags"><span class="stp-05__tag">Dark Mode</span><span class="stp-05__tag">Custom Palette</span><span class="stp-05__tag">Font Scale</span></div>
</div>
<div class="stp-05__panel-inner" data-panel="2">
<div class="stp-05__panel-title">Invite Your Team</div>
<div class="stp-05__panel-desc">Add teammates by email. Assign roles and set permissions for each member.</div>
<div class="stp-05__tags"><span class="stp-05__tag">Admin</span><span class="stp-05__tag">Editor</span><span class="stp-05__tag">Viewer</span></div>
</div>
<div class="stp-05__panel-inner active" data-panel="3">
<div class="stp-05__panel-title">Connect Integrations</div>
<div class="stp-05__panel-desc">Link your favourite tools — Slack, GitHub, Figma, Linear and more — to keep everything in sync.</div>
<div class="stp-05__tags"><span class="stp-05__tag">Slack</span><span class="stp-05__tag">GitHub</span><span class="stp-05__tag">Figma</span><span class="stp-05__tag">Linear</span><span class="stp-05__tag">Notion</span></div>
<div class="stp-05__progress">
<svg class="stp-05__ring" viewBox="0 0 44 44">
<circle class="bg" cx="22" cy="22" r="20"/>
<circle class="fg" id="stp-05-ring" cx="22" cy="22" r="20"/>
</svg>
<div>
<div class="stp-05__pct" id="stp-05-pct">40%</div>
<div class="stp-05__pct-label">Overall Progress</div>
</div>
</div>
</div>
<div class="stp-05__panel-inner" data-panel="4">
<div class="stp-05__panel-title">Configure Analytics</div>
<div class="stp-05__panel-desc">Set up event tracking, conversion goals, and dashboard widgets to stay on top of performance.</div>
<div class="stp-05__tags"><span class="stp-05__tag">Events</span><span class="stp-05__tag">Goals</span><span class="stp-05__tag">Funnels</span></div>
</div>
<div class="stp-05__panel-inner" data-panel="5">
<div class="stp-05__panel-title">🚀 Ready to Launch!</div>
<div class="stp-05__panel-desc">Your workspace is fully configured. Click Launch to go live and start collaborating with your team.</div>
<div class="stp-05__tags"><span class="stp-05__tag">All systems go</span><span class="stp-05__tag">5 steps complete</span></div>
</div>
<div class="stp-05__nav">
<button class="stp-05__btn stp-05__btn--prev" id="stp-05-prev">← Previous</button>
<button class="stp-05__btn stp-05__btn--next" id="stp-05-next">Continue →</button>
</div>
</div>
</div>
</div>
```
## CSS
```css
.stp-05,
.stp-05 *,
.stp-05 *::before,
.stp-05 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.stp-05 ::selection {
background: #059669;
color: #fff;
}
.stp-05 {
--bg: #041a14;
--card: #071f18;
--emerald: #10b981;
--teal: #14b8a6;
--lime: #84cc16;
--dark: #d1fae5;
--muted: #2d6a54;
--border: #0d3d2e;
--white: #ecfdf5;
font-family: 'Segoe UI',system-ui,sans-serif;
background: var(--bg);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 40px 20px;
background-image: radial-gradient(ellipse at 30% 60%,rgba(16,185,129,.08) 0%,transparent 55%), radial-gradient(ellipse at 80% 20%,rgba(20,184,166,.06) 0%,transparent 40%);
}
.stp-05__wrap {
max-width: 700px;
width: 100%;
}
.stp-05__label {
font-size: 10px;
letter-spacing: .16em;
text-transform: uppercase;
color: var(--emerald);
font-weight: 700;
text-align: center;
margin-bottom: 12px;
}
.stp-05__title {
font-size: 26px;
font-weight: 800;
color: var(--white);
text-align: center;
letter-spacing: -.02em;
margin-bottom: 40px;
}
/* stepper */
.stp-05__stepper {
display: flex;
align-items: flex-start;
gap: 0;
margin-bottom: 48px;
}
.stp-05__item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
position: relative;
}
/* connector */
.stp-05__item:not(:last-child)::after {
content: '';
position: absolute;
top: 32px;
left: calc(50% + 32px);
width: calc(100% - 64px);
height: 2px;
background: var(--border);
transition: background .5s ease;
}
.stp-05__item.done::after {
background: linear-gradient(90deg,var(--emerald),var(--teal));
animation: stp-05-flash .4s ease;
}
@keyframes stp-05-flash {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
/* icon bubble */
.stp-05__bubble {
width: 64px;
height: 64px;
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 26px;
background: var(--border);
border: 2px solid var(--muted);
transition: all .4s cubic-bezier(.34,1.56,.64,1);
position: relative;
overflow: hidden;
}
.stp-05__bubble::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg,rgba(255,255,255,.05),transparent);
opacity: 0;
transition: opacity .3s;
}
.stp-05__item.done .stp-05__bubble {
background: linear-gradient(135deg,rgba(16,185,129,.25),rgba(20,184,166,.15));
border-color: var(--emerald);
box-shadow: 0 0 24px rgba(16,185,129,.3),inset 0 1px 0 rgba(255,255,255,.1);
}
.stp-05__item.done .stp-05__bubble::before {
opacity: 1;
}
.stp-05__item.active .stp-05__bubble {
background: linear-gradient(135deg,rgba(16,185,129,.15),rgba(132,204,22,.1));
border-color: var(--teal);
box-shadow: 0 0 0 6px rgba(16,185,129,.1),0 0 32px rgba(16,185,129,.3);
animation: stp-05-bob 2.5s ease-in-out infinite;
}
@keyframes stp-05-bob {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-4px);
}
}
/* checkmark overlay */
.stp-05__check {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 22px;
background: linear-gradient(135deg,var(--emerald),var(--teal));
border-radius: 18px;
opacity: 0;
transform: scale(.5);
transition: all .3s cubic-bezier(.34,1.56,.64,1);
}
.stp-05__item.done .stp-05__check {
opacity: 1;
transform: scale(1);
}
.stp-05__name {
font-size: 12px;
font-weight: 600;
color: var(--muted);
text-align: center;
letter-spacing: .04em;
text-transform: uppercase;
transition: color .3s;
}
.stp-05__item.done .stp-05__name {
color: var(--emerald);
}
.stp-05__item.active .stp-05__name {
color: var(--white);
}
.stp-05__sub {
font-size: 11px;
color: var(--border);
text-align: center;
transition: color .3s;
}
.stp-05__item.active .stp-05__sub {
color: var(--muted);
}
.stp-05__item.done .stp-05__sub {
color: var(--muted);
}
/* content panel */
.stp-05__panel {
background: var(--card);
border: 1px solid var(--border);
border-radius: 18px;
padding: 28px 32px;
min-height: 200px;
position: relative;
overflow: hidden;
}
.stp-05__panel::before {
content: '';
position: absolute;
top: -60px;
right: -60px;
width: 180px;
height: 180px;
border-radius: 50%;
background: radial-gradient(circle,rgba(16,185,129,.08),transparent);
}
.stp-05__panel-inner {
display: none;
}
.stp-05__panel-inner.active {
display: block;
animation: stp-05-in .35s ease;
}
@keyframes stp-05-in {
from {
opacity: 0;
transform: translateX(10px);
}
to {
opacity: 1;
transform: none;
}
}
.stp-05__panel-title {
font-size: 18px;
font-weight: 700;
color: var(--white);
margin-bottom: 8px;
}
.stp-05__panel-desc {
font-size: 14px;
color: var(--muted);
line-height: 1.7;
margin-bottom: 20px;
}
.stp-05__tags {
display: flex;
gap: 8px;
flex-wrap: wrap;
margin-bottom: 20px;
}
.stp-05__tag {
padding: 4px 12px;
border-radius: 999px;
font-size: 11px;
font-weight: 600;
background: rgba(16,185,129,.12);
border: 1px solid rgba(16,185,129,.25);
color: var(--emerald);
}
.stp-05__nav {
display: flex;
justify-content: space-between;
margin-top: 24px;
}
.stp-05__btn {
padding: 10px 24px;
border-radius: 10px;
border: none;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: all .2s;
}
.stp-05__btn--prev {
background: var(--border);
color: var(--muted);
}
.stp-05__btn--prev:hover {
color: var(--white);
}
.stp-05__btn--next {
background: linear-gradient(135deg,var(--emerald),var(--teal));
color: #fff;
box-shadow: 0 4px 16px rgba(16,185,129,.3);
}
.stp-05__btn--next:hover {
transform: translateY(-1px);
box-shadow: 0 8px 24px rgba(16,185,129,.4);
}
/* progress ring */
.stp-05__progress {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
margin-bottom: 20px;
}
.stp-05__ring {
width: 52px;
height: 52px;
}
.stp-05__ring circle {
fill: none;
stroke-width: 4;
stroke-linecap: round;
}
.stp-05__ring .bg {
stroke: var(--border);
}
.stp-05__ring .fg {
stroke: var(--emerald);
stroke-dasharray: 126;
stroke-dashoffset: 126;
transform: rotate(-90deg);
transform-origin: center;
transition: stroke-dashoffset .5s ease;
}
.stp-05__pct {
font-size: 13px;
font-weight: 700;
color: var(--emerald);
}
.stp-05__pct-label {
font-size: 12px;
color: var(--muted);
}
@media (prefers-reduced-motion: reduce) {
.stp-05__item.active .stp-05__bubble {
animation: none;
}
.stp-05__item.done::after,
.stp-05__panel-inner.active {
animation: none;
}
}
```
## JavaScript
```js
(function(){
let cur=3;
const items=document.querySelectorAll('.stp-05__item');
const panels=document.querySelectorAll('.stp-05__panel-inner');
const ring=document.getElementById('stp-05-ring');
const pct=document.getElementById('stp-05-pct');
const total=5;
function update(){
items.forEach((item,i)=>{
item.classList.remove('done','active','is-done');
if(i+1<cur) item.classList.add('done');
else if(i+1===cur) item.classList.add('active');
});
panels.forEach(p=>{
p.classList.remove('active');
if(parseInt(p.dataset.panel)===cur) p.classList.add('active');
});
const p=((cur-1)/(total-1)*100).toFixed(0);
const offset=126-(126*(cur-1)/(total-1));
ring.style.strokeDashoffset=offset;
pct.textContent=p+'%';
document.getElementById('stp-05-prev').disabled=cur<=1;
document.getElementById('stp-05-next').textContent=cur===total?'Launch 🚀':'Continue →';
}
document.getElementById('stp-05-prev').addEventListener('click',()=>{cur=Math.max(1,cur-1);update();});
document.getElementById('stp-05-next').addEventListener('click',()=>{cur=Math.min(total,cur+1);update();});
update();
})();
```How this works
Each step node is a circle holding an emoji icon. When a step becomes .is-done, a ::after pseudo fades in as a green checkmark overlay using opacity and scale transitions. The active node shows a double-ring glow via layered box-shadow.
The SVG ring progress tracker uses a <circle> with stroke-dasharray set to the full circumference. JS calculates the percentage complete and updates stroke-dashoffset directly on the element, producing a smooth arc fill. The ring rotates -90deg via CSS transform so it starts at the top.
Make it yours
- Swap emoji icons for SVG icons by replacing the text content inside each
.stp-05__iconnode. - Change the ring size by editing the SVG
width/heightattributes and recalculatingstroke-dasharrayas2 * Math.PI * r. - Edit
--emeraldand--tealat.stp-05to retheme the ring, nodes, and connector lines in one change. - Add a step label below each icon by inserting a
spansibling — the flex column layout accommodates it without restructuring. - Animate the ring fill by adding a CSS
transition: stroke-dashoffset .5s easeon the circle element.
Gotchas — read before shipping
- SVG
stroke-dashoffsetupdates are not transitioned by default — add the transition in CSS, not inline, or the fill jumps instantly. - The
::aftercheckmark usesposition:absolute— ensure each.stp-05__nodehasposition:relativeor the overlay escapes the circle. - Emoji rendering varies by OS — test the icon set on Windows, macOS, and Android before deploying.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 88+ | 14+ | 78+ | 88+ |
SVG stroke-dashoffset is supported in all modern browsers since 2015.