# Tracker

> A React status tracker: a row of status blocks over time, one per day, hour or deploy, for uptime pages, sync health and habit streaks.

- Type: React chart component (Charts & Stats)
- 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 tracker`
- Docs: https://wingo-ui.com/components/tracker

## Interaction

The first time the tracker scrolls into view its blocks rise from the bottom in one quick left-to-right sweep. Hover a block for a readout above the bar with its date, status and note; the block lifts and the others fade back (the nearest block answers, so thin blocks and gaps never flicker). Click a block to fire onBlockClick. On a phone the whole bar is the target: a tap pins the readout above it, a sideways drag scrubs through the days while a vertical drag still scrolls the page, a second tap on the same block opens it and a tap outside clears the readout. On narrow screens fit="latest" keeps only the newest blocks that fit and the start caption follows. With the keyboard, Tab lands on the bar (the newest block), Left / Right walk the blocks, Home / End jump to the ends, PageUp / PageDown move by ten, Enter or Space fire onBlockClick and Escape clears; a polite live region reads each block ("Degraded on August 14, 2026: Slow responses from the portal"). Screen readers get a summary of the counts per status and a table of every block. When a sliding window gains a block, the row glides one slot left and the new block rises in; status changes crossfade.

## Installation

```bash
npx wingo-ui@latest add 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/tracker` (needs the @wingo-ui registry with your API key in components.json)

Files:

- `components/ui/tracker.tsx`

npm dependencies: `npm i motion`

Wingo UI dependencies (installed automatically):

- [Chart kit](https://wingo-ui.com/components/chart-kit) ([Markdown](https://wingo-ui.com/components/chart-kit.md))
- [Date utils](https://wingo-ui.com/components/date-utils) ([Markdown](https://wingo-ui.com/components/date-utils.md))
- [useLocale](https://wingo-ui.com/components/use-locale) ([Markdown](https://wingo-ui.com/components/use-locale.md))
- [Motion presets](https://wingo-ui.com/components/motion) ([Markdown](https://wingo-ui.com/components/motion.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 { Tracker, type TrackerDatum } from "@/components/ui/tracker"

const data: TrackerDatum[] = [
  { date: "2026-09-18", status: "ok" },
  { date: "2026-09-19", status: "degraded", description: "Higher response times" },
  { date: "2026-09-20", status: "ok" },
  { date: "2026-09-21", status: "ok" },
  { date: "2026-09-22", status: "ok" },
  { date: "2026-09-23", status: "ok" },
  { date: "2026-09-24", status: "ok" },
]

export function EinvoicingStatus() {
  return (
    <Tracker
      data={data}
      label="Tax e-invoicing sync"
      summary="99.82%"
      locale="en-US"
      statuses={{
        ok: { label: "Operational", tone: "success" },
        degraded: { label: "Degraded", tone: "warning" },
        down: { label: "Down", tone: "danger" },
      }}
      onBlockClick={(datum) => console.log(datum.date)}
    />
  )
}
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `data` | `TrackerDatum[] = { id?: string; date?: string; status: string; label?: ReactNode; description?: ReactNode }[]` |  | One entry per block, oldest first. date is an iso day or date-time (the tooltip title and captions), label replaces the date as the title ("Deploy #482"), description is the note under the status. id (or the date) keys the update animations. |
| `statuses?` | `Record<string, { label: string; tone?: Tone; color?: string }>` |  | Merged over the defaults key by key: ok (success, "Operational"), degraded (warning, "Degraded"), down (danger, "Outage"), maintenance (info, "Maintenance") and none (foreground at 10%, "No data"). Overriding only a label keeps the default tone and color ({ none: { label: "No data" } }). color takes any CSS color, a palette slot ("series-3") or a tone name and wins over tone. Your own keys come first in the legend. Unknown keys draw as none with a dev warning. |
| `label?` | `ReactNode` | `""` | The title at the start of the header; also names the figure for screen readers. |
| `summary?` | `ReactNode` | `""` | The figure at the end of the header, e.g. the uptime. |
| `size?` | `"sm" \| "md" \| "lg"` | `"md"` | Block height: 24 / 32 / 40px. On touch screens the tap target grows to at least 44px either way. |
| `radius?` | `"none" \| "sm" \| "md" \| "full"` | `"sm"` | Block corners: 0 / 2 / 3px, or pills. |
| `gap?` | `number` | `2` | Pixels between blocks. With fit="all" it shrinks when the blocks would not fit otherwise. |
| `fit?` | `"latest" \| "all"` | `"latest"` | latest: blocks keep minBlockWidth and the oldest drop off on narrow screens (the start caption follows). all: every block squeezes, down to 1px. |
| `minBlockWidth?` | `number` | `4` | The narrowest a block gets with fit="latest", in px. |
| `showCaptions?` | `boolean` | `true` | Start and end captions under the bar ("90 days ago", "Today"), from labels.start and labels.end. |
| `showLegend?` | `boolean` | `false` | The statuses present in the shown blocks, as keys with labels. |
| `showTooltip?` | `boolean` | `true` | The readout on hover, tap and keyboard. The live region and the table still carry every block when off. |
| `tooltipMode?` | `"auto" \| "float" \| "fixed"` | `"fixed"` | fixed pins the readout above the bar, centered on the block; float rides beside it; auto floats with a mouse and pins on touch. |
| `onBlockClick?` | `(datum: TrackerDatum, index: number) => void` |  | A click, a second tap on a pinned block, or Enter / Space on the inspected block. index is the position in data. |
| `locale?` | `string` | `""` | Locale for the dates. Empty uses the UIProvider / LocaleProvider locale. |
| `animated?` | `boolean` | `true` | The sweep on first view and the slide when blocks are appended. Reduced motion always shows the final state. |
| `loading?` | `boolean` | `false` | A pulsing skeleton in the bar's shape, plus the summary and captions. |
| `emptyState?` | `ReactNode` |  | Replaces the bar when data is empty. Default: the kit's empty state with labels.empty. |
| `description?` | `string` | `""` | A one-sentence takeaway for screen readers, read before the counts per status. |
| `labels?` | `Partial<TrackerLabels>` |  | Strings: start(count, first), end (string or (last) => string), block(status, date), summary(counts, total), table, date, status, note, loading, empty, inspectHint. English by default ("90 days ago", "Today", "Degraded on 14 August 2026"). |
| `classNames?` | `Partial<Record<TrackerSlot, string>>` |  | Classes for header, label, summary, bar, block, footer, legend, tooltip and table. |

## Parts

### DEFAULT_TRACKER_STATUSES (constant)

The built-in statuses that statuses merges over: ok ("Operational", success), degraded ("Degraded", warning), down ("Outage", danger), maintenance ("Maintenance", info) and none ("No data", foreground at 10%).

### DEFAULT_TRACKER_LABELS (constant)

The English strings: start ("90 days ago"), end ("Today"), block ("Degraded on" plus the date), summary, table, date, status, note, loading, empty and inspectHint. Spread it into labels to translate a few.

### TrackerDatum (type)

One block: { id?, date?, status, label?, description? }. status is a key of statuses; label replaces the date in the tooltip ("Deploy #482").

### TrackerStatus (type)

One status: { label, tone?, color? }. color takes any CSS color, a palette slot or a tone name and wins over tone.

### TrackerLabels (type)

The shape of the labels object, with start, end, block and summary as functions.

## Examples

- **Status page**: Three integrations, each with its uptime.
- **Deliveries with a legend**: Custom statuses, size lg and showLegend.
- **Sizes, radii and gaps**: A habit streak in neutral ink, down to pill blocks.
- **Hourly**: 24 blocks for today with hour captions and tooltip titles.
- **Fit on a phone**: fit="latest" vs fit="all" in 360px frames.
- **Live updates**: A sliding window of deploys with onBlockClick.
- **Loading and empty**: The bar-shaped skeleton and the empty state.

## See also

- [Status Page](https://wingo-ui.com/templates/status-page) ([Markdown](https://wingo-ui.com/templates/status-page.md))
- [Heatmap calendar](https://wingo-ui.com/components/heatmap-calendar) ([Markdown](https://wingo-ui.com/components/heatmap-calendar.md))
- [GitHub Activity](https://wingo-ui.com/components/github-activity) ([Markdown](https://wingo-ui.com/components/github-activity.md))
- [Sparkline](https://wingo-ui.com/components/sparkline) ([Markdown](https://wingo-ui.com/components/sparkline.md))
- [Chart kit](https://wingo-ui.com/components/chart-kit) ([Markdown](https://wingo-ui.com/components/chart-kit.md))

---

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