Order tracker React component for Tailwind CSS v4
v1.0.0Added in 1.0.0
A React order tracker: status, arrival window, milestones, a courier route, the tracking number, shipment history and the order total.
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.
Order tracker is a Pro React component in the React commerce components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add order-tracker, together with Alert, Avatar, Badge, Button, Copy Button and 12 more and the npm packages lucide-react and motion.
Add to a project
Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup
npx wingo-ui@latest add order-trackerOrder tracker is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans
Usage
Import OrderTracker from @/components/ui/order-tracker.
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
orderNumber*default"#1042"stringThe order number in the heading ("Order #1042") and what the copy button copies.
statusdefault"shipped""placed" | "confirmed" | "shipped" | "out-for-delivery" | "ready-for-pickup" | "delivered" | "failed" | "cancelled" | "returned"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.
placedAtTimeInputWhen the order was placed, under the number ("Placed 22.09.2026, 10:14").
eta{ from: TimeInput; to?: TimeInput } | stringThe 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".
etaNotedefault""ReactNodeA muted line under the arrival ("Handed over in person", "The courier calls 15 minutes before").
deliveredAtTimeInputWith status delivered the arrival line reads "Delivered today at 11:24".
milestonesOrderMilestone[] ({ 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.
eventsdefault"[]"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.
historyLimitdefault3numberEvents shown before the Show full history button.
courierOrderCourier ({ 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.
itemsOrderTrackerItem[] ({ id; title: string; image?: string; quantity: number; price: number })Overlapping thumbnails, "4 items", the titles and the total.
totaldefault0numberThe total shown by the items. 0 sums the items (price times quantity) through lib/commerce.
mapReactNode | falseYour 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.
animateddefaulttruebooleanfalse 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.
showMapdefaulttruebooleanThe route illustration (or your map). Not shown for cancelled and returned orders.
showHistorydefaulttruebooleanThe shipment history section.
showItemsdefaulttruebooleanThe items row with the total.
noticeReactNode | { 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.
variantdefault"card""card" | "page"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).
sizedefault"md""sm" | "md"sm is the compact card of an orders list: the header, the arrival line and the milestones.
actionsReactNodeButtons at the end (contact, report a problem, return). They stack full width on a phone.
tonedefault"neutral""neutral" | "brand" | "success" | "warning" | "danger" | "info"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.
colordefault""stringAny CSS color; replaces the tone while the order is in progress. Leave empty to use the tone.
nownumber | Date | nullThe reference time for "today", the delay check and the day headings. Default: the live clock (useNow), null while hydrating.
linkComponent(props: LinkComponentProps) => ReactNodeRenders the tracking link; default: the LinkProvider's link, else <a>.
currencydefault"USD"stringISO 4217 code of the total.
localedefault""stringIntl locale for dates, times, counts and the total. Empty uses the UIProvider locale, then the page.
labelsPartial<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.
classNamesPartial<Record<"header" | "status" | "eta" | "milestones" | "map" | "courier" | "pickup" | "history" | "items" | "actions", string>>Extra classes for the inner parts.
classNamestringExtra classes for the root section, merged last.
Parts
DEFAULT_ORDER_TRACKER_LABELS
constantEvery 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
constantThe 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.
Dependencies
Files
- components/ui/order-tracker.tsx
FAQ
Is the React Order tracker component free?
The preview, props and docs are free; copying the source needs a Pro plan. See plans.
How do I install Order tracker?
Run npx wingo-ui@latest add order-tracker. It also adds the Wingo UI items it builds on (Alert, Avatar, Badge, Button, Copy Button and 12 more) and the npm packages lucide-react and motion. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/order-tracker.
How does Order tracker behave on phones?
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.
See also
Used in
More React commerce components
Articles using this component
- Order History Page Design: List, Detail and Actions
Build it: screens and apps9 min read

