Team Progress Bar
alphav0.2.1Read-only team progress bar showing milestone completion — optional ticks and numeric readout, cooperative by design.
Context
The header cue for a gamified team board: answers "how far is our team through the journey?" to build competence (SDT) without tipping into comparison. Takes either a Milestone[] (computes done/total) or a direct value (0–100); draws a signal-lime fill on the shadcn progress primitive, optionally overlays per-milestone tick notches and a percent/fraction readout, animates the fill on change (reduced-motion aware), and emits progress-bar.checked once when first scrolled into view. Ships as a light shadcn-style compound — headless TeamProgressBarRoot (resolves the % + owns telemetry + holds context) + flat parts (TeamProgressBarTrack, TeamProgressBarLabel) + a context-free ProgressTrack primitive + the TeamProgressBar assembly — so a bar-only header falls out by dropping the Label. Cooperative-only and team-scoped by design (system D-08): one team's own % only — never another team's bar, a leaderboard, a ranking, or a per-member split. Portable: zero next/*, no app context, no other registry import; SSR-safe; all data is the host's. First component of the gamification-system.
Installation
pnpm dlx shadcn@latest init"registries": {
"@ilinxa": "https://ui.ilinxa.com/r/{name}.json"
}pnpm dlx shadcn@latest add @ilinxa/team-progress-barAdd -fixtures for dummy data:
pnpm dlx shadcn@latest add @ilinxa/team-progress-bar-fixturesPreview
From milestones, with ticks
% = done / total · per-milestone notches · fraction readout · emits progress-bar.checked on first view
Standalone, direct value
The simplest drop-in — a 0–100 number, no milestone infrastructure.
Composed / lighter (bar only, no label)
Hand-assembled Root + Track — drop the Label and it tree-shakes away.
Edge cases
Always visible — empty renders 0%, never nothing; 0% and 100%; no team name.
Demo source
Usage
When to use
Reach for TeamProgressBar in a team-board header to answer one question at a glance: how far is our team through the journey? It shows a single, always-visible, read-only bar of this team's milestone-completion % — built for competence (SDT) without tipping into comparison. It is cooperative and team-scoped by design: no other team's bar, no ranking, no per-member split — ever.
Two input modes
milestones— the component computesdone / total, enabling tick marks and the"fraction"readout.value— a direct 0–100 number for the simplest drop-in. If both are supplied,valuewins (and dev-warns).
Basic example
import { TeamProgressBar } from "@/components/team-progress-bar"
export function BoardHeader({ team }) {
return (
<TeamProgressBar
team={{ id: team.id, name: team.name }}
milestones={team.milestones} // % = done / total
showTicks
labelFormat="fraction" // "5 / 8 milestones"
onEvent={(e) => analytics.track(e.type, e)} // host adds the envelope
/>
)
}Compose a lighter version
It ships as a light shadcn-style compound. Drop the parts you don't need — a bar-only header tree-shakes the label away:
import {
TeamProgressBarRoot, TeamProgressBarTrack,
} from "@/components/team-progress-bar"
<TeamProgressBarRoot team={{ id: "T-001" }} milestones={team.milestones}>
<TeamProgressBarTrack showTicks /> {/* no Label part */}
</TeamProgressBarRoot>Notes
- Always visible. No milestones yet (
total === 0) renders a 0% bar, never nothing. - Telemetry is a feature-view.
onEventemitsprogress-bar.checkedonce per mount, on first in-viewport reveal — not on every render. OmitonEventand no observer is created. - Accessible. The bar is a
role="progressbar"witharia-valuenow/min/max; ticks are decorative-but-labelled; the fill transition respectsprefers-reduced-motion. - Portable. No
next/*, no app context, no other registry import — only the shadcnprogressprimitive.
Features
- One team's milestone-completion % — done/total from a Milestone[], or a direct 0–100 value
- Always visible, read-only: no milestones yet renders a 0% bar, never nothing
- Optional per-milestone tick notches (filled = done, in order) + percent/fraction readout
- Signal-lime fill with a reduced-motion-aware transition; one reveal-up entrance
- progress-bar.checked telemetry — emitted once per mount on first in-viewport reveal
- Cooperative + team-scoped: no comparison, second series, ranking, or per-member split — ever
- Light compound: headless Root + flat parts + context-free ProgressTrack; drop the Label for a free bar-only header