webdevpuneet.com

Progress Circle Steps — Free HTML CSS JS Step Progress Bar

Progress Circle Steps · Loaders · Plain HTML, CSS & JS · Live preview

CategoryLoaders

Copy & paste

Source Code

<div class="ps-wrap">
  <div class="ps-steps" id="psSteps">
    <div class="ps-step is-done" data-label="Cart"><span class="ps-node">1</span><span class="ps-name">Cart</span></div>
    <div class="ps-step is-current" data-label="Shipping"><span class="ps-node">2</span><span class="ps-name">Shipping</span></div>
    <div class="ps-step" data-label="Payment"><span class="ps-node">3</span><span class="ps-name">Payment</span></div>
    <div class="ps-step" data-label="Review"><span class="ps-node">4</span><span class="ps-name">Review</span></div>
  </div>
  <div class="ps-actions">
    <button type="button" class="ps-btn" id="psBack">Back</button>
    <button type="button" class="ps-btn ps-primary" id="psNext">Next</button>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Circular numbered nodes
Digits that become checks when done.
Filling connector
The line turns green up to the current step.
Three-state styling
Upcoming, current, and done from classes.
Morphing check
Number swaps to a tick with no extra markup.
Single source of truth
One index drives the whole indicator.
Back-jump nav
Click any completed node to return to it.
Forward guard
Cannot skip ahead past undone steps.
Finish state
Last step turns Next into Finish.

About this UI Snippet

Progress Circle Steps — A Numbered Wizard Progress Bar

Screenshot of the Progress Circle Steps snippet rendered live

The progress circle steps indicator is the horizontal "1 — 2 — 3 — 4" tracker at the top of checkouts and multi-step forms, where completed steps turn into green check circles and the connector between them fills in as you advance. This snippet builds it with plain HTML, CSS, and a small vanilla JavaScript state machine.

Nodes and connectors

Each step is a flex column holding a circular node and a label. The connecting line is a ::after on every step except the last, positioned absolutely at the node's vertical centre and stretched across the gap behind the circles (z-index: 0 so the nodes sit on top). When a step is marked done, its connector turns green — so the line literally fills up to the current step, giving an at-a-glance sense of progress.

Three node states from classes

A step is in one of three states driven entirely by CSS classes: upcoming (muted circle with its number), current (accent border and a soft focus ring around the node), or done (solid green circle showing a check mark instead of the number). The check is a ::after content swap with the number's font-size set to zero, so the same node element morphs from a digit to a tick without extra markup. Smooth transition: all on the node makes each change animate.

A tiny state machine

JavaScript holds a single current index and a render() function that re-derives every step's classes from it — done if before current, current if equal, upcoming otherwise — plus the button states. This is the cleanest way to drive a stepper: one number is the source of truth, and the whole indicator is a pure function of it, so there's no chance of two steps both appearing current.

Navigation, including back-jumps

Next advances the index (and the final Next becomes "Finish"), Back decrements it and disables at the first step, and clicking any node at or before the current step jumps straight back to it — letting users revisit a completed step without clicking Back repeatedly. Forward jumps to undone steps are blocked, so you can't skip ahead past required steps.

Accessible structure

The labels are real text under each node, so the steps are readable and not conveyed by colour alone. The disabled Back button uses the native disabled attribute, and the markup is plain enough to extend with aria-current="step" on the active step for screen readers.

Customizing it

Add or remove steps freely — the flex layout and index logic adapt — change the accent and done colours, or wire render() to also show the matching form panel for each step. Pair it with a multi-step form, a progress wizard, or a stepper.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA four-step tracker renders at step two.
  2. 2
    Click NextThe current step completes and fills the line.
  3. 3
    Reach the endThe Next button label becomes Finish.
  4. 4
    Click BackIt steps back and disables at the first step.
  5. 5
    Click a past nodeJump straight to any completed step.
  6. 6
    Add a stepDrop in another .ps-step — logic adapts.

Real-world uses

Common Use Cases

Checkout stage trackers
Show Cart, Shipping, Payment and Review above a checkout form, with completed steps becoming green check circles.
Multi-step form headers
Place above a multi-step form so people know how many steps remain, with clickable back-navigation to completed ones.
Wizard and stepper alternatives
Compare with a progress wizard or a richer stepper when your step labels need more detail than circles allow.
Order status trails
Adapt the connector for an order tracking timeline, where the filled line stops at the current stage.
Setup flow guides
Guide new accounts alongside an onboarding checklist widget, with upcoming, current and done states set purely by classes.
Related: Staggered Skeleton List Reveal
See the Staggered Skeleton List Reveal for a related loaders pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

Each step except the last has a ::after line positioned behind the nodes. When a step is marked done its connector turns green, so the line fills up to the current step. Because done is derived from the current index, the fill always matches how far the user has advanced.

The done node keeps the same element but sets the number's font-size to zero and adds a check as ::after content, so the circle morphs from a digit to a tick without extra markup. A transition on the node animates the colour and border change smoothly as a step completes.

A single current index is the source of truth, and a render function re-derives every step's classes from it — done before current, current when equal, upcoming after — plus the button states. Because the whole indicator is a pure function of one number, two steps can never both appear current.

Yes. Clicking any node at or before the current step sets the index to it, so users can revisit a completed step without repeatedly clicking Back. Forward jumps past undone steps are blocked, so the guard prevents skipping required steps while still allowing free backward navigation.

Hold the current step index in state and render each step's done/current classes from it, exactly like the render function. Wire Next and Back to increment and decrement the index, and node clicks to jump back when the index is less than or equal to current. The node, connector, and check CSS port unchanged.