Component

PercentileSurfaces

Precise linear percentile surfaces for scouting rows, cards, and battle-test recreations. PercentileBar is the primary precision read; PercentilePill is the dense companion for list rows.

Progressive passesBig Five League midfielders877.4 /90
Stories

Canonical behaviors.

Baseline bar list

A single player's scouting row rendered as stacked PercentileBars. Every bar carries the same comparison sample; the inversion badge appears on 'Dispossessed' because originalDirection === 'lower'.

Progressive passesBig Five League midfielders877.4 /90Key passesBig Five League midfielders742.1 /90Expected assistsBig Five League midfielders820.27 /90Tackles wonBig Five League midfielders581.8 /90InterceptionsBig Five League midfielders641.2 /90Dispossessedlower is better711.4 /90
Empty state (NaN percentile)

Invalid input never paints a fake zero bar. The empty-state primitive renders inside the SVG and the warnings channel receives a named reason.

Invalid percentile value
Pill row stack

Dense scouting list built from 14 PercentilePill components. Composition — not a runtime fallback — is how small-card layouts are handled.

Touches91Pass completion %88Progressive carries76Successful dribbles69Fouls drawn62Progressive passes87Key passes74Expected assists82Tackles won58Interceptions64Dispossessed71LIBDribbled past53LIBAerials won41
Hybrid overview + precision

RadarChart gives the profile shape, PercentileBar list gives the exact percentiles. Same fixture, two normalization shapes derived from one source row set.

525507595Progressive passesKey passesExpected assistsTackles wonInterceptionsDispossessed
Possession
Creation
Defending
Ball security
Progressive passesBig Five League midfielders877.4 /90Key passesBig Five League midfielders742.1 /90Expected assistsBig Five League midfielders820.27 /90Tackles wonBig Five League midfielders581.8 /90InterceptionsBig Five League midfielders641.2 /90Dispossessedlower is better711.4 /90
Quiet recipe

percentileBarRecipes.quiet mutes the track and softens the fill for card-sidebar usage. Callers can still override individual families on top.

Progressive passesBig Five League midfielders877.4 /90
Usage

Best-practice examples.

Minimal percentile bar

Pass a single metric and a comparison sample. The bar handles sample labeling, tick placement, and the accessible label.

                    import { PercentileBar } from "@withqwerty/campos-react";

export function ProgPasses({ metric, comparison }) {
  return <PercentileBar metric={metric} comparison={comparison} />;
}
                  
Pill row stack

Compose dense scouting rows from PercentilePill. Each pill requires either a comparison sample or an explicit accessibleSampleLabel fallback.

                    import { PercentilePill, percentilePillRecipes } from "@withqwerty/campos-react";

export function PillRow({ metric, comparison }) {
  return (
    <PercentilePill
      metric={metric}
      comparison={comparison}
      recipe={percentilePillRecipes.compact}
    />
  );
}
                  
Hybrid overview + precision

Pair a RadarChart overview with a PercentileBar list so readers can see both the profile shape and the exact values. The same fixture drives both charts.

                    import { PercentileBar, RadarChart } from "@withqwerty/campos-react";

export function ScoutingCard({ radarRows, percentileMetrics, comparison }) {
  return (
    <div className="grid gap-4 md:grid-cols-[1fr_1.2fr]">
      <RadarChart rows={radarRows} />
      <ul className="space-y-1">
        {percentileMetrics.map((metric) => (
          <li key={metric.id}>
            <PercentileBar metric={metric} comparison={comparison} />
          </li>
        ))}
      </ul>
    </div>
  );
}
                  
API

Public surface.

Prop Type Default Description
metric PercentileMetric Single metric packet: id, label, display-scale percentile (higher is always better), optional rawValue/rawValueUnit, and optional originalDirection used to drive the inversion badge and the accessible inversion note.
comparison PercentileComparisonSample — (required on the bar; required-or-fallback on the pill) Named comparison sample (e.g. 'Big Five League midfielders'). The pill also accepts an accessibleSampleLabel fallback when the sample line is suppressed visually.
inversionBadgeLabel string "lower is better" Copy shown in the inversion badge when originalDirection === 'lower'. Set to an empty string to hide the visible badge; the inversion note remains in the structured accessibleLabel.
onWarnings (warnings: readonly string[]) => void Called on mount when the compute layer returned any warnings (e.g. clamped percentile, weak sample). Components also emit one dev-only console.warn per unique warnings signature.
track / fill / text / ticks / badges StyleValue-backed style family First-class styling surfaces that accept constants, object-maps, or callbacks. Constant-only subsets flow through the static export contract for PercentileBar.
recipe PercentileBarRecipe | PercentilePillRecipe Named preset (percentileBarRecipes.quiet, percentilePillRecipes.compact). Individual style-family overrides still win at the prop level.
Use with AI
LLM Prompt
Create a React component using Campos PercentileBar. Import PercentileBar from @withqwerty/campos-react, keep metric and comparison shaping outside the component, and require an explicit comparison sample label (or an accessibleSampleLabel fallback for PercentilePill).