# Order tracker

> A React order tracker: status, arrival window, milestones, a courier route, the tracking number, shipment history and the order total.

- Type: React component (Commerce)
- Access: Pro (the source needs a Wingo UI Pro plan, see https://wingo-ui.com/pricing)
- Version: 1.0.0
- Install: `npx wingo-ui@latest add order-tracker`
- Docs: https://wingo-ui.com/components/order-tracker

## Interaction

Read it top to bottom: the order number (with a copy button), a status badge, when it arrives ("Arrives today between 5:00 PM and 7:00 PM"), five milestones, an illustrated route where the travelled part draws in when it scrolls into view and the courier dot rides its end, then glides on to the next point when the status changes (it pulses while out for delivery, never under reduced motion or off screen). Tap the phone button to call the courier, the copy buttons to copy the order number, the tracking number or the locker PIN, and the tracking link to open the courier's page in a new tab. "Show full history" unfolds the older events (each with its day and time) one after another; press it again to fold them. Tab reaches every button and link once, Enter and Space press them. On a phone the milestones become a "Step 4 of 5" header with a bar, the call button is 44px and the actions stack full width; the page variant puts the history beside the details from about 768px of width.

## Installation

```bash
npx wingo-ui@latest add order-tracker
```

Pro item: run `npx wingo-ui@latest login` once with a Pro account. The CLI adds the files, their dependencies and a version record for updates.

With shadcn: `npx shadcn@latest add @wingo-ui/order-tracker` (needs the @wingo-ui registry with your API key in components.json)

Files:

- `components/ui/order-tracker.tsx`

npm dependencies: `npm i lucide-react motion`

Wingo UI dependencies (installed automatically):

- [Alert](https://wingo-ui.com/components/alert) ([Markdown](https://wingo-ui.com/components/alert.md))
- [Avatar](https://wingo-ui.com/components/avatar) ([Markdown](https://wingo-ui.com/components/avatar.md))
- [Badge](https://wingo-ui.com/components/badge) ([Markdown](https://wingo-ui.com/components/badge.md))
- [Button](https://wingo-ui.com/components/button) ([Markdown](https://wingo-ui.com/components/button.md))
- [Copy Button](https://wingo-ui.com/components/copy-button) ([Markdown](https://wingo-ui.com/components/copy-button.md))
- [Price](https://wingo-ui.com/components/price) ([Markdown](https://wingo-ui.com/components/price.md))
- [Steps](https://wingo-ui.com/components/steps) ([Markdown](https://wingo-ui.com/components/steps.md))
- [Timeline](https://wingo-ui.com/components/timeline) ([Markdown](https://wingo-ui.com/components/timeline.md))
- [useLocale](https://wingo-ui.com/components/use-locale) ([Markdown](https://wingo-ui.com/components/use-locale.md))
- [Commerce](https://wingo-ui.com/components/commerce) ([Markdown](https://wingo-ui.com/components/commerce.md))
- [Date utils](https://wingo-ui.com/components/date-utils) ([Markdown](https://wingo-ui.com/components/date-utils.md))
- [Motion presets](https://wingo-ui.com/components/motion) ([Markdown](https://wingo-ui.com/components/motion.md))
- [Navigation](https://wingo-ui.com/components/navigation) ([Markdown](https://wingo-ui.com/components/navigation.md))
- [Number format](https://wingo-ui.com/components/number-format) ([Markdown](https://wingo-ui.com/components/number-format.md))
- [Relative time](https://wingo-ui.com/components/relative-time) ([Markdown](https://wingo-ui.com/components/relative-time.md))
- [Tones](https://wingo-ui.com/components/tones) ([Markdown](https://wingo-ui.com/components/tones.md))
- [UIProvider](https://wingo-ui.com/components/ui-config) ([Markdown](https://wingo-ui.com/components/ui-config.md))

## Usage

```tsx
import { Button } from "@/components/ui/button"
import { OrderTracker, type OrderEvent } from "@/components/ui/order-tracker"

const events: OrderEvent[] = [
  { id: "e3", title: "Out for delivery", description: "Driver Michael Brooks", time: "2026-09-24T08:12:00", status: "out-for-delivery" },
  { id: "e2", title: "Handed to the courier", location: "Newark, NJ", time: "2026-09-22T15:40:00", status: "shipped" },
  { id: "e1", title: "Order placed", time: "2026-09-22T10:14:00", status: "placed" },
]

export function Order() {
  return (
    <OrderTracker
      orderNumber="#1042"
      status="out-for-delivery"
      placedAt="2026-09-22T10:14:00"
      eta={{ from: "2026-09-24T17:00:00", to: "2026-09-24T19:00:00" }}
      events={events}
      courier={{
        name: "FedEx",
        trackingNumber: "2345 6789 012",
        trackingUrl: "https://www.fedex.com/fedextrack/",
        driver: { name: "Michael Brooks", phone: "(212) 555-0147" },
      }}
      items={[{ id: "p1", title: "City bike", quantity: 1, price: 1199 }]}
      currency="USD"
      locale="en-US"
      labels={{ order: (n) => `Order ${n}`, eta: (w) => `Arrives ${w}` }}
      actions={<Button variant="soft">Contact support</Button>}
    />
  )
}
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `orderNumber` | `string` | `"#1042"` | The order number in the heading ("Order #1042") and what the copy button copies. |
| `status?` | `"placed" \| "confirmed" \| "shipped" \| "out-for-delivery" \| "ready-for-pickup" \| "delivered" \| "failed" \| "cancelled" \| "returned"` | `"shipped"` | Drives the badge and its color, the milestones (when not given), the arrival line and where the courier sits on the route. Ended orders (delivered, failed, cancelled, returned) paint in their status color; an unknown value shows as is in a neutral badge. |
| `placedAt?` | `TimeInput` |  | When the order was placed, under the number ("Placed 22.09.2026, 10:14"). |
| `eta?` | `{ from: TimeInput; to?: TimeInput } \| string` |  | The arrival window, written relative to now ("Arrives today between 17:00 and 19:00", "tomorrow", a weekday, then the date), or free text. A window that has passed while the order still moves turns the badge into "Delayed". |
| `etaNote?` | `ReactNode` | `""` | A muted line under the arrival ("Handed over in person", "The courier calls 15 minutes before"). |
| `deliveredAt?` | `TimeInput` |  | With status delivered the arrival line reads "Delivered today at 11:24". |
| `milestones?` | `OrderMilestone[] ({ id; label: ReactNode; status?: "complete" \| "current" \| "upcoming" \| "error"; time?: TimeInput })` |  | Default: Placed, Confirmed, Shipped, Out for delivery, Delivered (Ready for pickup and Picked up for locker orders), each dated from the first matching event and its state derived from status. A failed or cancelled order shows the error on the step where it stopped. |
| `events?` | `OrderEvent[] ({ id; title: ReactNode; description?: ReactNode; location?: string; time: TimeInput; status?: OrderStatus; icon?: ReactNode })` | `"[]"` | The shipment history, newest first, each event with its day ("Today", "Yesterday", a weekday, then the date) and time. Each status brings its icon; the newest event takes its status color. Empty hides the section. |
| `historyLimit?` | `number` | `3` | Events shown before the Show full history button. |
| `courier?` | `OrderCourier ({ name; logo?: ReactNode; trackingNumber?; trackingUrl?; phone?; driver?: { name; avatar?; phone? } })` |  | The courier tile: logo or a truck, the driver with an avatar, a call button (tel:, until the parcel is delivered or returned), the tracking number with a copy button and the tracking link (new tab). Hidden while none is known and when the order is cancelled. |
| `pickup?` | `{ name: string; address: string; code?: string; until?: TimeInput }` |  | A locker or store pickup. Switches the milestones to Ready for pickup / Picked up and, while ready for pickup, replaces the courier with the locker, the PIN (large, with a copy button) and the deadline. |
| `items?` | `OrderTrackerItem[] ({ id; title: string; image?: string; quantity: number; price: number })` |  | Overlapping thumbnails, "4 items", the titles and the total. |
| `total?` | `number` | `0` | The total shown by the items. 0 sums the items (price times quantity) through lib/commerce. |
| `map?` | `ReactNode \| false` |  | Your own map (an embed, an image) in place of the illustration, or false to hide it. The default illustration is decorative (aria-hidden) with a caption. |
| `animated?` | `boolean` | `true` | false draws the route at once and stops every pulse (the courier dot, the badge), for thumbnails and static pages. Reduced motion does the same on its own. |
| `showMap?` | `boolean` | `true` | The route illustration (or your map). Not shown for cancelled and returned orders. |
| `showHistory?` | `boolean` | `true` | The shipment history section. |
| `showItems?` | `boolean` | `true` | The items row with the total. |
| `notice?` | `ReactNode \| { title?: ReactNode; description?: ReactNode; actions?: ReactNode; tone?: Tone }` |  | An inline alert under the arrival: the reason of a failed attempt and the next try, a refund note. A failed order without one shows the description of its newest failed event. |
| `variant?` | `"card" \| "page"` | `"card"` | card: everything in one panel. page: sections for a full page (status, map, courier and items, with the history in a column beside them once the tracker is about 768px wide). |
| `size?` | `"sm" \| "md"` | `"md"` | sm is the compact card of an orders list: the header, the arrival line and the milestones. |
| `actions?` | `ReactNode` |  | Buttons at the end (contact, report a problem, return). They stack full width on a phone. |
| `tone?` | `"neutral" \| "brand" \| "success" \| "warning" \| "danger" \| "info"` | `"neutral"` | The milestones, the arrival icon and the route while the order is in progress (a failed or cancelled order keeps it on the milestones, where the stopped step shows in amber for a failed attempt and red for a cancellation). Ended orders paint the rest in the exported ORDER_STATUS_TONES instead (placed and confirmed neutral, shipped, out for delivery and ready for pickup info, delivered success, failed warning, cancelled danger, returned neutral), so the end state always reads the same; reuse it for your own order badges. |
| `color?` | `string` | `""` | Any CSS color; replaces the tone while the order is in progress. Leave empty to use the tone. |
| `now?` | `number \| Date \| null` |  | The reference time for "today", the delay check and the day headings. Default: the live clock (useNow), null while hydrating. |
| `linkComponent?` | `(props: LinkComponentProps) => ReactNode` |  | Renders the tracking link; default: the LinkProvider's link, else <a>. |
| `currency?` | `string` | `"USD"` | ISO 4217 code of the total. |
| `locale?` | `string` | `""` | Intl locale for dates, times, counts and the total. Empty uses the UIProvider locale, then the page. |
| `labels?` | `Partial<OrderTrackerLabels>` |  | Every string, English by default (exported as DEFAULT_ORDER_TRACKER_LABELS, spread it under your own): order (n) => "Order #1042", placedOn, status per OrderStatus, delayed, milestones (placed, confirmed, shipped, outForDelivery, delivered, readyForPickup, pickedUp), steps (Steps labels: progress, step, next), eta, window, at, delivered, trackingNumber, copyOrderNumber, copyTrackingNumber, copyPickupCode, copied, track, newTab, callCourier, pickupCode, pickupUntil, history, showAll, showLess, items (count, formatted), total, mapLabel. |
| `classNames?` | `Partial<Record<"header" \| "status" \| "eta" \| "milestones" \| "map" \| "courier" \| "pickup" \| "history" \| "items" \| "actions", string>>` |  | Extra classes for the inner parts. |
| `className?` | `string` |  | Extra classes for the root section, merged last. |

## Parts

### DEFAULT_ORDER_TRACKER_LABELS (constant)

Every English string of the tracker: the heading, status names, milestones, arrival window, copy buttons, pickup code, history and total. Spread it under your own labels.

### ORDER_STATUS_TONES (constant)

The tone of each order status (shipped info, delivered success, failed warning, cancelled danger, the rest neutral). Reuse it to color your own order badges the same way.

## Examples

- **Delivered**: The arrival line becomes "Delivered today at 11:24 AM", every milestone checks off and the route turns green.
- **Failed attempt**: A warning notice with the reason, the next window and a reschedule action; the milestones stop at the failed step.
- **Locker pickup**: The locker, a large PIN to copy and the pickup deadline replace the courier.
- **Orders list**: size="sm": the header, the arrival and the milestones, three orders in three states.
- **Page with your own map**: variant="page" and tone="brand", with an image in the map slot; the history moves beside the details when there is room.
- **Cancelled**: The milestones stop after Confirmed and a refund note explains what happens next.
- **Euro total, another courier**: A euro total with en-US times, a driver photo and no map.

## See also

- [Timeline](https://wingo-ui.com/components/timeline) ([Markdown](https://wingo-ui.com/components/timeline.md))
- [Steps](https://wingo-ui.com/components/steps) ([Markdown](https://wingo-ui.com/components/steps.md))
- [Copy Button](https://wingo-ui.com/components/copy-button) ([Markdown](https://wingo-ui.com/components/copy-button.md))
- [Price](https://wingo-ui.com/components/price) ([Markdown](https://wingo-ui.com/components/price.md))
- [Commerce](https://wingo-ui.com/components/commerce) ([Markdown](https://wingo-ui.com/components/commerce.md))

---

Canonical: https://wingo-ui.com/components/order-tracker
More components: https://wingo-ui.com/components · Index for agents: https://wingo-ui.com/llms.txt
