Data✨ Premium

Progress Steps

Numbered step indicator: the current step lights up indigo, previous ones turn green and the line linking them fills in.

CSSJSSteps

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Data has 28 effects, including 1 free. Explore the category →

3 usage examples

A bakery's click-and-collect checkout — Progress Steps example 1

① A bakery's click-and-collect checkout

WhenAt the top of a bakery's checkout: Basket, Pick-up, Payment, Confirmed. The content of the step shows underneath and the "Continue" button (or a click on the page, for the capture) moves the indicator and the content forward together.
WhyKnowing how many steps remain before paying is reassuring; the filling line shows the ground already covered.
Settings--pgs-max-width:none, --pgs-dot-size:32px, current #b45309 (golden brown), completed #15803d, empty dots white with a beige border, bold 11.5 px labels.
Progress of a watch repair in a watchmaker's customer area — Progress Steps example 2

② Progress of a watch repair in a watchmaker's customer area

WhenA repair page in "My account": the watch face, the job number, then the Received, Diagnosis, In the workshop, Ready tracker with a status sentence below. The scene moves the job forward every 1.2 s, up to data-current="5" where all four steps are completed.
WhyA repair takes days and customers wonder where their watch is: the indicator answers at a glance, and the sentence below gives the detail (quote accepted, 48-hour check) without calling the shop.
Settings--pgs-dot-size:28px, fir-green palette (--pgs-active:#2f5d43; --pgs-done:#7aa386), rail #e1e8e2, 11 px labels, transparent background inside a white card.
Solved puzzles in the corner of an online escape game — Progress Steps example 3

③ Solved puzzles in the corner of an online escape game

WhenA puzzle screen: the riddle, an answer field and a "Check" button. In the top-right corner, four small dots count the solved puzzles. In the scene, a click types the right answer, checks it, and the next dot lights up with its violet glow.
WhyIn a game, progress must stay discreet yet always visible: 150 px are enough to say "two locks to go".
Settings--pgs-max-width:150px, --pgs-dot-size:20px, current #a855f7 with a rgba(168,85,247,.7) glow, completed #22c55e, 9 px labels.

How it works

The steps form an ordered list <ol class="pgs-list">; each <li class="pgs-step"> holds a .pgs-dot and a .pgs-label. The connecting lines are not extra elements: they are the ::before (grey rail) and ::after (green-to-indigo fill) pseudo-elements of every step except the first.

The current step is read from the root's data-current attribute. The script sets .pgs-done on earlier steps, .pgs-current and aria-current="step" on the current one; the CSS colours the dot (green, or indigo with a glow) and stretches the line fill (scaleX, 0.6 s). With data-current set to the number of steps plus one, all of them are completed.

One MutationObserver per instance watches data-current: root.setAttribute('data-current', 3) is enough to move forward or back. When the indicator scrolls into view, it starts from the first step and fills the next ones one by one (0.25 s apart) up to the current step.

The number of steps is up to you; they share the width (up to --pgs-max-width, 420 px) and long labels wrap under their dot.

Accessibility

  • Ordered list and current step: a screen reader announces "list, 4 items", then each step with its number and label; the current step carries aria-current="step".
  • State in words, not only colour: completed steps get visually hidden text "(completed)" ("(terminée)" on a French page), so green is not the only cue.
  • Reduced motion: under prefers-reduced-motion: reduce, colours and lines change without transition and the final state shows as soon as it appears.
  • An indicator, not navigation: steps are not clickable. If users must be able to go back to a step, put links or buttons inside the labels and handle them yourself.

Browser compatibility

Flexbox, pseudo-elements, transform and colour transitions, MutationObserver, IntersectionObserver. Measured in Chromium 151, Firefox 153 and WebKit 26.5: two independent indicators on one page (changing one leaves the other alone), line half-filled at 150 ms, 390 px, white background, no JS error.

Chrome 51+✓ Full (measured)
Firefox 55+✓ Full (measured)
Safari 12.1+✓ WebKit engine measured, not checked in real Safari
Edge 79+✓ Full (Chromium engine)
Safari iOS 12.2+✓ Not checked on a real device
Chrome Android 51+✓ Full (Chromium engine)

Without JavaScript all dots and labels show in grey, with no highlighted step: the list stays readable.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0248-root" data-current="2">
  <ol class="pgs-list" aria-label="Order steps">
    <li class="pgs-step"><span class="pgs-dot">1</span><span class="pgs-label">Cart</span></li>
    <li class="pgs-step"><span class="pgs-dot">2</span><span class="pgs-label">Info</span></li>
    <li class="pgs-step"><span class="pgs-dot">3</span><span class="pgs-label">Pay</span></li>
    <li class="pgs-step"><span class="pgs-dot">4</span><span class="pgs-label">Done</span></li>
  </ol>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
data-current (HTML, on the root) 2 Number of the current step (1 = the first). The number of steps plus one marks everything as completed.
Steps (HTML) 4: Cart, Info, Pay, Done Add or remove <li class="pgs-step"> items; numbers and labels are free.
--pgs-active, --pgs-glow (CSS) #6366f1, rgba(99,102,241,.5) Colour and glow of the current step.
--pgs-done, --pgs-fill (CSS) #10b981, green → indigo gradient Colour of completed steps and of the filled line.
--pgs-idle, --pgs-idle-border, --pgs-text, --pgs-text-on (CSS) 8% white, 15% white, 40% white, 80% white Upcoming dots and labels; replace them with dark tones on a light background.
--pgs-dot-size, --pgs-max-width (CSS) 36px, 420px Dot size (lines realign on it) and maximum width.
--pgs-speed (CSS) .6s Duration of a line fill.
--pgs-bg, --pgs-min-height (CSS) #0a0a0f, 300px Root background and minimum height.

FAQ

In the code that shows your form's next step, add indicator.setAttribute('data-current', number). The script observes the attribute; there is no global function to call and several indicators can live side by side.
Set data-current to the number of steps plus one (5 for four steps): every dot turns green and every line is filled, with no step marked as current.
Each step takes an equal share of the width and its label wraps inside that share. Keep labels to one or two words, or raise --pgs-max-width; on mobile, five steps with labels over ten letters become hard to read.