Goal tracker
ProA team goals card where objectives open into key results with owners, confidence and progress bars. A weekly check-in updates a value, confidence and note in place, fills the bar and recalculates the objective, and a quarter selector steps from last quarter's final scores to next quarter's planning.
- Showing a team's quarterly objectives and key results with owners and confidence.
- Collecting a lightweight weekly check-in (value, confidence, note) without leaving the page.
- Comparing the active quarter against last quarter's final scores.
- A single KPI with a trend line; use a metric or stat card.
- Task or project tracking with assignees and due dates; use a task list or kanban block.
- Org-wide goal trees with parent and child alignment; this card is one level deep.
Installation
Pro source and install commands unlock with a Pro plan.
Usage
Pass `quarters` (each with id, label, status of active, closed or planning, optional meta and footnote, and objectives with key results). For each key result, set start, target and current in the metric's own units. The card works out progress itself, so a target below the start value (latency, cost) works with no extra setup. Save check-ins in `onCheckIn(checkIn, { signal })`. The card updates once the promise resolves. If it throws, the form shows "Not saved" and a Retry button. Control the selector with `quarterId` and `onQuarterChange`, and set `autoPlay={false}` in production. Helpers (`keyResultProgress`, `objectiveProgress`, `formatGoalValue`) and `sampleGoalQuarters` are exported.
import { GoalTracker, type GoalCheckIn, type GoalQuarter } from "@/components/arc/blocks/goal-tracker/goal-tracker"; export function TeamGoals({ quarters }: { quarters: GoalQuarter[] }) { return ( <GoalTracker title="Platform goals" quarters={quarters} onCheckIn={async (checkIn: GoalCheckIn, { signal }) => { const response = await fetch("/api/check-ins", { method: "POST", body: JSON.stringify(checkIn), signal }); if (!response.ok) throw new Error("Check-in failed"); }} /> );}API reference
3 parts. The first is the root.
GoalTracker
A team goals card. Objectives expand into key results with owners, confidence and progress bars; a key result opens a weekly check-in that updates its value, confidence and note, animates the bar and recalculates the objective. A quarter selector steps between closed, active and planning quarters. With no props it shows sample Q4 2026 goals and plays one check-in.
quartersGoalQuarter[]sampleGoalQuartersQuarters, oldest first. Each has id, label, status (active, closed or planning), optional meta and footnote lines, and objectives. Seeds the card; saved check-ins update it in place.titlestring"Company goals"Card heading.quarterIdstring–Selected quarter id. Pair with onQuarterChange to control the selector.defaultQuarterIdstringthe active quarterQuarter shown first when uncontrolled.onQuarterChange(quarterId: string) => void–Called when the person steps to another quarter.onCheckIn(checkIn: GoalCheckIn, context: { signal: AbortSignal }) => Promise<void> | void–Saves a check-in: quarterId, objectiveId, keyResultId, value, previousValue, confidence and note. Throw to show the error state with Retry; the signal aborts when the person cancels. Leave it out to simulate a save.autoPlaybooleantrue with sample data, false with your ownPlays one scripted check-in the first time the card scrolls into view. Any pointer or key input hands control back at once.classNamestring–Extra class on the card.GoalKeyResult
One measurable result. Progress runs from start to target, so a target below start (latency, cost, ticket counts) also works.
idRequiredstring–Stable id, returned in GoalCheckIn.titleRequiredstring–What success looks like, such as "Checkout p95 latency under 400 ms".startRequirednumber–Value when the quarter began.targetRequirednumber–Value that counts as 100%.currentRequirednumber–Latest checked in value.prefixstring–Text before the number, such as "$".unitstring–Text after the number, such as "%", " ms" or "k".decimalsnumber0Decimal places shown and pre-filled in the check-in.confidenceRequired"on-track" | "at-risk" | "off-track"–Owner's confidence, shown as an icon and label and as the bar color.source{ name: string; icon?: ReactNode }–Where the number is synced from, shown as a small mark (Stripe, Linear, Vercel in the sample).GoalObjective
An objective with its owner and key results. Progress is the mean of its key results; confidence is their rounded mean.
idRequiredstring–Stable id.titleRequiredstring–The objective.ownerRequired{ name: string; avatar?: string }–Owner shown with an avatar; initials when there is no image.keyResultsRequiredGoalKeyResult[]–Two to five key results reads best.- Tab
- Moves through the quarter buttons, objectives, key results and the footer Check in button.
- EnterorSpace
- On an objective, expands or collapses it. On a key result, opens its check-in with the value selected.
- Arrow keys
- In the check-in, moves between On track, At risk and Off track.
- Enter
- In the check-in, saves.
- Escape
- Cancels the check-in and returns focus to the key result.
- Objectives are disclosure buttons with aria-expanded and aria-controls; collapsed bodies are inert.
- Each key result button has a label with its value, target, progress and confidence, so the visual bar is not the only source.
- Confidence is always an icon plus a text label, never color alone.
- The check-in is a labelled form; the hidden form and hidden key results are inert so focus never lands on invisible controls.
- A polite live region announces saves, errors and the recalculated objective, and says when a save was simulated.
- Bars fill once when the card first scrolls into view, then tween to new values (560ms ease-out) with percentages counting in tabular numerals.
- The objective bar follows its key result 120ms later so cause and effect read clearly.
- Key results and the check-in form share one grid cell and crossfade (100ms out, 160ms in), so the card never changes height when the form opens.
- Objective bodies open with a bounce-free 240ms spring on measured height; quarters crossfade with an 8px directional shift and the empty state borrows the previous height.
- Reduced motion keeps the end states, crossfades and feedback, and drops the fill travel, shifts and the scripted demo.
- Fluid from 360px to 640px wide using container queries, so it adapts to its column rather than the viewport.
- Below 480px the bars shorten and the confidence picker moves under the value field; below 380px owner names collapse to avatars.
- Titles truncate with an ellipsis; numbers, labels and bars never wrap or shift.
- Progress animations run on motion values and clip-path, so numbers and bars update without React re-renders.
- One IntersectionObserver for the first fill and one ResizeObserver for the quarter height; both disconnect on unmount.
- Designed for up to about five objectives with five key results each per quarter.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Use for OKRs, team goals or quarterly targets inside a product: a settings or team page, a dashboard column, or a weekly review.
- Pass real data through quarters and persist check-ins in onCheckIn; the card updates optimistically after the promise resolves, and shows Retry if it throws.
- Set start, target and current in the metric's own units; the card computes progress, so decreasing targets need no special handling.
- Set autoPlay={false} in production. The sample data plays one demo check-in by default.
- Keep one card per team; for many teams, stack cards rather than adding more objectives to one card.
The full library index for assistants is at /llms.txt.