Tracker Features¶
The Tracker page is more than a list — it carries visual signals (sparklines, drift badges, autopay trust), URL-backed state (sorting, filtering, search panel), and accessibility features (keyboard navigation, reduced-motion respect) that make the monthly planning loop faster.
This page documents those features in detail and links them to the underlying services. For the basic layout (rows, columns, buckets), see Plan a Month in the Tracker.
What does the sparkline on a Tracker row mean?¶
Each Tracker row renders a 44 × 16 px inline SVG polyline of the last six months of actual payment totals for that bill, oldest-to-newest, normalized to the row's own min/max range.
| Property | Value |
|---|---|
| Size | 44 × 16 px |
| Render | Inline SVG <polyline> — no chart library |
| Data source | trackerService.fetchSparklines |
| Query | Single batched GROUP BY bill_id, month_str for all bill IDs at once |
| Visibility | Renders only when two or more months of data exist |
The sparkline is computed on the server for every active bill in the current tracker request — it is not a per-bill lazy fetch. As a result, the Tracker load time grows by one additional query, not by N.
What the sparkline tells you
A flat polyline near the top of the cell means a bill like Verizon has held steady at its expected amount for six months. A polyline that dips in the last segment tells you the most recent payment was lower than the prior five — a candidate for a one-time amount override.
What does the "Changed" badge mean?¶
When the drift service flags a bill — the current month's amount differs
from the prior month's by more than the configured threshold — the
Tracker amount column shows a small amber Changed badge with a
TrendingUp icon.
| Property | Value |
|---|---|
| Data source | Existing useDriftReport() data already fetched by TrackerPage |
| Network cost | None — isDrifted is derived per row from the bill ID set |
| Hover behaviour | Tooltip repeats the same expected → actual delta shown in the price-change insights panel |
The badge is intentionally a thin visual signal: it does not block the row, and clicking it jumps to the same update flow as the insights panel. The drift threshold is per-bill and editable in Add and Manage Bills.
How do I sort the Tracker?¶
Click any column header on the desktop table to toggle sort direction.
The filter bar exposes a compact sort selector for mobile and tablet.
The URL is bookmarkable:
/tracker?year=2026&month=5&sort=due_day&dir=asc captures the active
view.
You can sort by:
| Sort key | What it shows |
|---|---|
name |
Bill name (alphabetical) |
due_day |
Due day within the current month, then by name |
expected |
Effective amount (expected with override applied) |
last_month_paid |
Total paid last month |
paid |
Total paid in the current cycle |
remaining |
Amount remaining in the current cycle |
paid_date |
Most recent paid date in the cycle |
status |
Lifecycle order (see below) |
Manual bill reordering is automatically disabled while a sorted view is active. The two modes are mutually exclusive — Pin Due, sort, and manual reorder are three different ways to organize the same rows, and the UI clearly tells you which is active.
Status sort is lifecycle-aware, not alphabetical
See the next question.
What order does the Status sort use?¶
status sort uses the lifecycle order rather than plain alphabetical
labels:
The values match the Status field on each row, so a user who "sorts by
status" gets a visual walk through the urgency gradient — overdue first,
already-paid last — not a textbook A-Z list.
Why do some screens animate?¶
framer-motion powers the Tracker:
| Surface | Animation |
|---|---|
| Page transitions | Shared PageTransition wrapper drives user/admin route content (opacity + small Y offset) |
| Dialogs and AlertDialogs | Framer entry motion (fade + scale-in) |
| Tracker bucket rows | LayoutGroup so sorted and reordered bill groups move smoothly between positions |
| Mobile rows | motion.div per row; quick-pay tap is debounced while a save is in progress |
| Bucket headers | Wrap cleanly on narrow screens without layout shift |
The animation respects useReducedMotion() — users with reduced-motion
preferences see content appear without motion. The animations are tuned
to be additive, not blocking: the row is interactive during the
animation, and a double-tap on Pay Now is intentionally debounced.
How do I collapse the search and filter panel?¶
Click the chevron in the search bar header. The expanded/collapsed state
is stored in the per-user search_bars_collapsed setting via the shared
useSearchPanelPreference hook, the same hook used by the Bills and
Subscriptions pages.
| Property | Value |
|---|---|
| Default | Expanded |
| Persistence | Per-user setting, shared across Tracker, Bills, and Subscriptions |
| Hook | useSearchPanelPreference in client/hooks/useSearchPanelPreference.js |
| Component | SearchFilterPanel (shared) |
When the panel is collapsed, only the search input and a "Filters" toggle button are visible; advanced filters open inline when toggled.
How do I navigate the Tracker with a keyboard?¶
Tracker rows are keyboard-navigable. Each row carries tabIndex={0},
data-tracker-row, aria-rowindex, and an aria-label that announces
the bill name, status, and due day.
| Key | Action |
|---|---|
↓ / j |
Focus the next row (crosses bucket boundaries) |
↑ / k |
Focus the previous row |
Enter |
Open the edit modal for the focused bill |
P |
Toggle paid / unpaid (skipped bills ignored) |
Esc |
Blur the row |
Cmd+P / Ctrl+P is intentionally passed through to the browser so
users can still print. The handler guards against firing on nested
interactive elements (if (e.target !== e.currentTarget) return).
How do I work through overdue bills faster?¶
A collapsible command center appears at the top of the Tracker when there is at least one overdue bill. Each overdue bill exposes:
- Pay Now — opens the payment dialog with the bill prefilled
- Skip — marks the bill skipped for the current month
- Snooze — 1 / 3 / 7 day options, persisted server-side
Snoozed bills are hidden from the overdue list with a count hint in the header so the user can see how many bills are temporarily suppressed without expanding the panel.
See also¶
- Plan a Month in the Tracker — the layout, columns, and lifecycle statuses
- Add and Manage Bills — the autopay trust and drift threshold that drive the badges
- Record Payments — what the Pay Now action does
- API Reference (v0.37) — the
/api/trackerand/api/bills/:id/verify-autopayendpoints
Next steps¶
- See the layout and columns in Plan a Month in the Tracker.
- Add or tune a bill in Add and Manage Bills.
- Record a payment from a row with Record Payments.
- Audit a slow Tracker in the Operations Runbook.