webdevpuneet.com

Order Tracking Timeline — HTML CSS JS Snippet

Order Tracking Timeline · Cards · Plain HTML, CSS & JS · Live preview

CategoryCards

Copy & paste

Source Code

<div class="ot-card">
  <div class="ot-head">
    <div>
      <div class="ot-order">Order #FWD-20418</div>
      <div class="ot-eta">Arriving <strong id="otEta">Thu, Jun 18</strong></div>
    </div>
    <div class="ot-status-pill" id="otPill">In transit</div>
  </div>

  <div class="ot-timeline" id="otTimeline">
    <div class="ot-rail"><div class="ot-rail-fill" id="otFill"></div></div>

    <div class="ot-step">
      <div class="ot-dot"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div>
      <div class="ot-body"><div class="ot-step-title">Order placed</div><div class="ot-step-time">Mon, Jun 15 · 9:41 AM</div></div>
    </div>
    <div class="ot-step">
      <div class="ot-dot"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div>
      <div class="ot-body"><div class="ot-step-title">Packed &amp; ready</div><div class="ot-step-time">Mon, Jun 15 · 4:12 PM</div></div>
    </div>
    <div class="ot-step">
      <div class="ot-dot"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div>
      <div class="ot-body"><div class="ot-step-title">Shipped</div><div class="ot-step-time">Tue, Jun 16 · 8:03 AM</div></div>
    </div>
    <div class="ot-step">
      <div class="ot-dot"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div>
      <div class="ot-body"><div class="ot-step-title">Out for delivery</div><div class="ot-step-time" id="otTime3">Pending</div></div>
    </div>
    <div class="ot-step">
      <div class="ot-dot"><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg></div>
      <div class="ot-body"><div class="ot-step-title">Delivered</div><div class="ot-step-time" id="otTime4">Pending</div></div>
    </div>
  </div>

  <button class="ot-btn" onclick="advanceStatus()">Simulate next update</button>
</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

Index-driven rendering
A single current index plus render controls the entire timeline — rail height, dot states, checkmarks, text emphasis, and the status pill all derive from it.
Animated progress rail
.ot-rail-fill grows its height to current / (steps − 1) with a cubic-bezier transition, so progress visibly climbs instead of snapping.
Three dot states
Steps below current go green with a scale-in checkmark, the current step pulses indigo, and the rest stay grey — instantly readable status.
Pure-CSS pulse
The active dot's attention pulse is a looping box-shadow keyframe — no JS timer, so it costs nothing and never drifts.
Checkmark pop-in
Completed dots animate their svg from scale(.4) and zero opacity to full, making each completed stage feel rewarding.
Status pill mirroring
The header pill always reflects the current stage label and recolours green on delivery to mark the terminal state.
Live timestamp fill-in
advanceStatus writes a real timestamp into each newly reached step, replacing its "Pending" placeholder.
Terminal completed state
On the final stage the rail hits 100%, the ETA flips to "today", and the action button disables with a "delivered" confirmation.

About this UI Snippet

Order Tracking Timeline — Animated Progress Rail, Pulsing Current Stage & Completed Checkmarks

Screenshot of the Order Tracking Timeline snippet rendered live

"Where is my order?" is the single most common post-purchase question, and a clear tracking timeline answers it before the customer has to email support. A good fulfilment timeline shows every stage from placed to delivered, marks what is done, highlights what is happening now, and animates as the order advances — turning anxious waiting into reassuring progress. This snippet implements that pattern in plain HTML, CSS, and vanilla JavaScript: a vertical timeline with an animated progress rail, checkmark-completed steps, a pulsing current stage, a status pill, and a live ETA.

The component is driven by a single current index and a render function — change the index, call render, and the entire visual state (rail height, dot colours, checkmarks, text emphasis, status pill) follows. That makes wiring it to real tracking events trivial.

Animated progress rail

Behind the dots runs a grey .ot-rail. Inside it, .ot-rail-fill is a green gradient whose height is set as a percentage of current / (steps − 1). A cubic-bezier transition animates the fill upward whenever the order advances, so progress visibly grows rather than jumping. The rail is positioned to line up exactly with the centre of each dot, and a higher z-index on the dots keeps them above the rail.

Three dot states: done, active, pending

Each step is classed by render: indices below current get .done (green dot with a checkmark that scales in), the index equal to current gets .active (an indigo dot with a pulsing ring), and the rest stay pending (grey). The checkmark svg animates from scale(.4) and opacity:0 to full size, so completing a step feels like a small reward. The active dot's pulse is a pure-CSS box-shadow keyframe that expands and fades on a loop — drawing the eye to the current stage without any JavaScript animation loop.

Status pill and ETA

A pill in the header mirrors the current stage label ("In transit", "Out for delivery"). On delivery, render recolours the pill green and updates the ETA text to "today" — small touches that make the final state feel distinct and complete.

Live advancement

The "Simulate next update" button calls advanceStatus, which increments current, fills in a real timestamp for the newly reached step, and re-renders. When the order reaches the final stage, the button disables and switches to "Order delivered ✓". In production you would call render from a websocket message, a polling fetch, or a server-sent event carrying the carrier's latest scan — the rendering code does not change.

Pair this timeline with an order summary of the items being shipped, a stepper for checkout progress, or a vertical timeline for general event histories.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSAn order-tracking card appears with five stages; the first three are complete with green checkmarks and "Shipped" pulses as the current stage.
  2. 2
    Read the current stateThe green rail fills up to the active stage, the header pill shows "In transit", and the ETA reads "Thu, Jun 18".
  3. 3
    Advance the orderClick "Simulate next update" — the rail animates up, "Shipped" turns into a checkmark, and "Out for delivery" starts pulsing with a real timestamp.
  4. 4
    Watch the pulse moveEach advance moves the indigo pulsing ring to the new current stage and updates the status pill to match.
  5. 5
    Reach deliveredAdvance to the final stage — the rail fills to 100%, every dot is a checkmark, the pill turns green, and the ETA changes to "today".
  6. 6
    See the completed buttonOnce delivered, the button disables and reads "Order delivered ✓", signalling there are no further updates.

Real-world uses

Common Use Cases

E-commerce shipment tracking
The core use — show order fulfilment from placed to delivered. Link it from an order summary or order-history row.
Food and grocery delivery
Stages like "Preparing", "On the way", and "Delivered" with the pulse on the live stage — ideal for real-time courier updates over websockets.
Service and repair status
Track a repair ticket or claim through received, diagnosed, in-progress, and completed. Reuse the dot states for any multi-stage workflow.
Onboarding and account setup
Show provisioning progress for a new account. For interactive multi-step flows, pair with a stepper or progress wizard.
Application and approval pipelines
Loan, visa, or job-application stages where applicants want to see exactly where their case stands and what happens next.
Project milestone history
Use it as a read-only history of events with timestamps, similar to a vertical timeline but with completion states.

Got questions?

Frequently Asked Questions

Map your carrier's status codes to step indices, set current to the latest reached step, and call render(). For live updates, subscribe to a websocket or poll a tracking endpoint; each message just updates current and the timestamps, then re-renders — no other code changes.

Switch the .ot-timeline layout to a row, lay the rail horizontally, and animate .ot-rail-fill width instead of height. The render logic stays identical — only the axis the percentage applies to changes. Horizontal works well on wide desktop layouts; vertical is better on mobile.

Add an .error state class with a red dot and an alert icon, and a status like "Delivery attempt failed". In render, branch when the current step carries an error flag so the rail stops at that point and the pill turns red, prompting the customer to take action.

Wrap the timeline in an aria-live="polite" region so advances are announced, mark completed steps with visually-hidden "completed" text and the current step with "in progress", and ensure the status pill text conveys state without relying on colour alone. The checkmarks should have an aria-hidden since the text already states completion.

In React, hold current in useState and derive each step's class from its index versus current; set the rail height from a computed percentage in the style prop. In Vue, use a ref for current and :class/:style bindings in a v-for. In Angular, track current on the component and bind [class.done]/[class.active]. The rail and pulse CSS port unchanged.