Skip to content
ilinxa/pro-ui

Team Progress Bar

alphav0.2.1

Read-only team progress bar showing milestone completion — optional ticks and numeric readout, cooperative by design.

Category: GamificationUpdated: 2026-08-11Created: 2026-07-01Author: ilinxa

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

Initialize shadcn (once per project)Seeds lib/utils.ts and components.json. Skip if you've already used any shadcn component.
pnpm dlx shadcn@latest init
Register the @ilinxa namespace (once per project)Add to your components.json. Merge with existing config.
"registries": {
  "@ilinxa": "https://ui.ilinxa.com/r/{name}.json"
}
Install the component
pnpm dlx shadcn@latest add @ilinxa/team-progress-bar

Add -fixtures for dummy data:

pnpm dlx shadcn@latest add @ilinxa/team-progress-bar-fixtures

Preview

From milestones, with ticks

% = done / total · per-milestone notches · fraction readout · emits progress-bar.checked on first view

Team Aurora5 / 8 milestones

Standalone, direct value

The simplest drop-in — a 0–100 number, no milestone infrastructure.

Team Aurora62%

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.

No milestones yet (total === 0)
Team Aurora0%
Just started (0%)
Team Aurora0%
Complete (100%)
Team Aurora100%
No team name
45%

Demo source

demo.tsxtsx

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 computes done / total, enabling tick marks and the "fraction" readout.
  • value — a direct 0–100 number for the simplest drop-in. If both are supplied, value wins (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. onEvent emits progress-bar.checked once per mount, on first in-viewport reveal — not on every render. Omit onEvent and no observer is created.
  • Accessible. The bar is a role="progressbar" with aria-valuenow/min/max; ticks are decorative-but-labelled; the fill transition respects prefers-reduced-motion.
  • Portable. No next/*, no app context, no other registry import — only the shadcn progress primitive.

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

Tags

team-progress-bargamificationprogressmilestonesteamcooperativetelemetry

Dependencies

shadcn primitives: progress