Order Tracking

Order #10482

Arriving

Track on UPS (opens the carrier’s website)
  1. Completed: Ordered
  2. Completed: Shipped
  3. Current step: In transit Today
  4. Upcoming: Out for delivery
  5. Upcoming: Delivered Expected
Carrier
UPS Standard
Tracking number
1Z999AA10123456784
Shipping to
Anna Smith, Budapest
Shipment history
  1. Departed facility Budapest, HU
  2. Arrived at the sorting center Budapest, HU
  3. Picked up by the carrier Győr, HU
  4. Shipping label created Győr, HU

Something wrong with the delivery? Contact support

@use 'sprucecss/scss/spruce' as *;

.order-tracking {
  --order-tracking-dot: 1.75rem;
  background-color: color('surface');
  border: config('border-width-base', $display) solid color('border');
  border-radius: radius('lg');
  padding: spacer-clamp('m', 'l');
  @include layout-stack('m');

  &__header {
    align-items: flex-end;
    display: flex;
    flex-wrap: wrap;
    gap: spacer('s');
    justify-content: space-between;
  }

  &__heading {
    @include layout-stack('xxs');
  }

  &__eyebrow {
    color: color('muted');
    font-size: config('font-size-sm', $typography);
    font-weight: 600;
  }

  &__title {
    font-size: font-size('h3');
  }

  // Vertical on phones, horizontal from the sm breakpoint.
  &__steps {
    display: grid;
    gap: spacer('s');
    // The parent's layout-stack sets the margins.
    list-style: none;
    padding: 0;
    position: relative;

    @include breakpoint('sm') {
      align-items: start;
      gap: spacer('xs');
      grid-auto-columns: minmax(0, 1fr);
      grid-auto-flow: column;
      text-align: center;

      // The track and its filled part, behind the dots.
      &::before,
      &::after {
        block-size: 3px;
        border-radius: radius('pill');
        content: '';
        inset-block-start: calc(var(--order-tracking-dot) / 2 - 1.5px);
        inset-inline-start: 10%;
        position: absolute;
      }

      &::before {
        background-color: color('border');
        inline-size: 80%;
      }

      &::after {
        background-color: color('primary');
        inline-size: calc(80% * var(--progress) / 100%);
      }
    }

    // The items sit side by side: clear the stack margins of the base list style.
    > li {
      margin-block: 0;
      padding-block: 0;
    }
  }

  &__step {
    align-items: center;
    display: grid;
    gap: 0 spacer('s');
    grid-template-columns: var(--order-tracking-dot) 1fr;
    hyphens: manual;
    line-height: config('line-height-md', $typography);
    position: relative;
    z-index: 1;

    @include breakpoint('sm') {
      gap: spacer('xxs');
      grid-template-columns: 1fr;
      justify-items: center;
    }
  }

  &__dot {
    align-items: center;
    aspect-ratio: 1;
    background-color: color('surface');
    border: 2px solid color('border-strong');
    border-radius: 50%;
    color: color('primary-foreground', 'btn');
    display: inline-flex;
    grid-row: span 2;
    inline-size: var(--order-tracking-dot);
    justify-content: center;

    svg {
      block-size: 0.875rem;
      inline-size: 0.875rem;
    }

    @include breakpoint('sm') {
      grid-row: auto;
    }
  }

  &__step--done &__dot {
    background-color: color('primary');
    border-color: color('primary');
  }

  &__step--current &__dot {
    border-color: color('primary');
    box-shadow: 0 0 0 4px color-alpha('primary', 0.2);

    &::before {
      aspect-ratio: 1;
      background-color: color('primary');
      border-radius: 50%;
      content: '';
      inline-size: 0.625rem;
    }
  }

  &__step-label {
    color: color('heading');
    font-weight: 600;
  }

  &__step--todo &__step-label {
    color: color('muted');
    font-weight: 400;
  }

  &__step-date {
    color: color('muted');
    font-size: config('font-size-sm', $typography);
  }

  &__details {
    background-color: color('surface-muted');
    border-radius: radius('md');
    display: grid;
    gap: spacer('s');
    grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
    margin-inline: 0;
    padding: spacer('s') spacer('m');

    dt {
      color: color('muted');
      font-size: config('font-size-sm', $typography);
      font-weight: 400;
    }

    dd {
      color: color('heading');
      font-weight: 600;
      margin: 0;
      @include word-wrap;
    }

    code {
      background: none;
      color: inherit;
      padding: 0;
    }
  }

  &__events {
    @include clear-list;
  }

  &__event {
    border-inline-start: 2px solid color('border');
    display: grid;
    margin: 0 0 0 spacer('xxs') !important;
    padding: 0 0 spacer('s') spacer('s');
    position: relative;

    &::before {
      aspect-ratio: 1;
      background-color: color('border-strong');
      border-radius: 50%;
      content: '';
      inline-size: 0.625rem;
      inset-block-start: 0.4rem;
      inset-inline-start: calc(-0.3125rem - 1px);
      position: absolute;
    }

    &:first-child::before {
      background-color: color('primary');
    }

    &:last-child {
      padding-block-end: 0;
    }
  }

  &__event-time,
  &__event-place {
    color: color('muted');
    font-size: config('font-size-sm', $typography);
  }

  &__event-text {
    color: color('heading');
    font-weight: 600;
  }

  &__help {
    color: color('muted');
    font-size: config('font-size-sm', $typography);
  }
}

[dir='rtl'] .order-tracking__event {
  margin: 0 spacer('xxs') 0 0 !important;
}
<section class="order-tracking" aria-labelledby="order-tracking-title">
    <header class="order-tracking__header">
        <div class="order-tracking__heading">
            <p class="order-tracking__eyebrow">Order #10482</p>
            <h3 class="order-tracking__title" id="order-tracking-title">Arriving <time datetime="2026-10-08">Thursday, October 8</time></h3>
        </div>
        <a class="btn btn--outline-secondary btn--sm" href="#">Track on UPS<span class="sr-only"> (opens the carrier’s website)</span></a>
    </header>
    <ol class="order-tracking__steps" role="list" style="--progress: 50%;">
            <li class="order-tracking__step order-tracking__step--done">
                <span class="order-tracking__dot" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg></span>
                <span class="order-tracking__step-label"><span class="sr-only">Completed: </span>Ordered</span>
                <span class="order-tracking__step-date"><time datetime="2026-10-03">Oct 3</time></span>
            </li>
            <li class="order-tracking__step order-tracking__step--done">
                <span class="order-tracking__dot" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M20 6 9 17l-5-5"/></svg></span>
                <span class="order-tracking__step-label"><span class="sr-only">Completed: </span>Shipped</span>
                <span class="order-tracking__step-date"><time datetime="2026-10-04">Oct 4</time></span>
            </li>
            <li class="order-tracking__step order-tracking__step--current" aria-current="step">
                <span class="order-tracking__dot" aria-hidden="true"></span>
                <span class="order-tracking__step-label"><span class="sr-only">Current step: </span>In transit</span>
                <span class="order-tracking__step-date">Today</span>
            </li>
            <li class="order-tracking__step order-tracking__step--todo">
                <span class="order-tracking__dot" aria-hidden="true"></span>
                <span class="order-tracking__step-label"><span class="sr-only">Upcoming: </span>Out for delivery</span>
            </li>
            <li class="order-tracking__step order-tracking__step--todo">
                <span class="order-tracking__dot" aria-hidden="true"></span>
                <span class="order-tracking__step-label"><span class="sr-only">Upcoming: </span>Delivered</span>
                <span class="order-tracking__step-date">Expected <time datetime="2026-10-08">Oct 8</time></span>
            </li>
    </ol>
    <dl class="order-tracking__details">
        <div><dt>Carrier</dt><dd>UPS Standard</dd></div>
        <div><dt>Tracking number</dt><dd><code>1Z999AA10123456784</code></dd></div>
        <div><dt>Shipping to</dt><dd>Anna Smith, Budapest</dd></div>
    </dl>
    <details class="order-tracking__history">
        <summary>Shipment history</summary>
        <ol class="order-tracking__events" role="list">
                <li class="order-tracking__event">
                    <time class="order-tracking__event-time" datetime="2026-10-04T18:42">Oct 4, 6:42 PM</time>
                    <span class="order-tracking__event-text">Departed facility</span>
                    <span class="order-tracking__event-place">Budapest, HU</span>
                </li>
                <li class="order-tracking__event">
                    <time class="order-tracking__event-time" datetime="2026-10-04T14:05">Oct 4, 2:05 PM</time>
                    <span class="order-tracking__event-text">Arrived at the sorting center</span>
                    <span class="order-tracking__event-place">Budapest, HU</span>
                </li>
                <li class="order-tracking__event">
                    <time class="order-tracking__event-time" datetime="2026-10-04T09:30">Oct 4, 9:30 AM</time>
                    <span class="order-tracking__event-text">Picked up by the carrier</span>
                    <span class="order-tracking__event-place">Győr, HU</span>
                </li>
                <li class="order-tracking__event">
                    <time class="order-tracking__event-time" datetime="2026-10-03T16:12">Oct 3, 4:12 PM</time>
                    <span class="order-tracking__event-text">Shipping label created</span>
                    <span class="order-tracking__event-place">Győr, HU</span>
                </li>
        </ol>
    </details>
    <p class="order-tracking__help">Something wrong with the delivery? <a href="#">Contact support</a></p>
</section>

Order Tracking

The delivery status of an order: the estimated arrival, a progress tracker, the shipment details and the scan history from the carrier.

Anatomy

  • .order-tracking__header: the order number, the arrival date as the title and a link to the carrier's tracking page.
  • .order-tracking__steps: an ordered list of steps (--done, --current, --todo). The --progress custom property (in percent) fills the line between the dots.
  • .order-tracking__details: a description list with the carrier, the tracking number and the address.
  • .order-tracking__history: a details element with the carrier events, newest first.

Accessibility and Usability

  • The current step has aria-current="step", and every step has a hidden state ("Completed:", "Current step:", "Upcoming:"), because the filled dots and the check marks are visual only.
  • The most important answer, "when will it arrive?", is the heading; the rest is supporting detail.
  • The link to the carrier has hidden text that says it leads to another site.
  • The long scan history is collapsed by default, but it's still a semantic ordered list with time elements.

Technical Details

  • No JavaScript: render the states and the --progress value on the server (for example, 50% at the third of five steps).
  • On phones, the steps are vertical; from the sm breakpoint, they're horizontal, and the line between them is drawn with ::before (the track) and ::after (the progress).
  • Keep it on the order page and link to it from the shipping confirmation email.

Documentation

Learn about Spruce CSS through our extensive documentation.

Components

Explore our UI library of accessible components built with Spruce CSS.

Blocks and Pages

Full-width page blocks and complete page templates, ready to copy.

Find us on GitHub

Did you find a bug? Have an idea or a question? Please open an issue to help us develop the project.