Skip to main content
Compendium / Metrics & Telemetry / Badges & Deltas / Percent Delta Chip
#723

Percent Delta Chip

A ±X.X% chip — period-over-period change normalised so deltas across metrics stay comparable.

STABLE DE
#badge #list #real-content #dark-mode-tested
Live
Throughput +12.4%
Error Rate -8.1%
Spec Churn 0.0%
Spec

Intent

Raw deltas favour large-scale metrics. Expressing change as a percent normalises movement so a +3 on a small base reads as the +60% it really is.

Acceptance Criteria

  • [ ] Signed percentage with one decimal place
  • [ ] Direction arrow paired with the value
  • [ ] Colour band reflects sign (success / danger / neutral)
  • [ ] Negative: does NOT render absolute deltas

Constraints

  • Pure markup, no JS
  • Theme-aware via tokens
// percent-delta-chip.astro
---
import type { CompendiumMeta } from '../../../data/types';

export const meta: CompendiumMeta = {
  id: 723,
  slug: 'percent-delta-chip',
  name: 'Percent Delta Chip',
  category: 'metrics-telemetry',
  subcategory: 'badges-and-deltas',
  pillar: 'de',
  description: 'A ±X.X% chip — period-over-period change normalised so deltas across metrics stay comparable.',
  spec: `## Intent
Raw deltas favour large-scale metrics. Expressing change as a percent normalises movement so a +3 on a small base reads as the +60% it really is.

## Acceptance Criteria
- [ ] Signed percentage with one decimal place
- [ ] Direction arrow paired with the value
- [ ] Colour band reflects sign (success / danger / neutral)
- [ ] Negative: does NOT render absolute deltas

## Constraints
- Pure markup, no JS
- Theme-aware via tokens`,
  tags: ['badge', 'list', 'real-content', 'dark-mode-tested'],
  status: 'stable',
  health: { ics: 87, a11y: 'aa', themed: true, animated: false },
};

const items = [
  { label: 'Throughput',  pct: 12.4 },
  { label: 'Error Rate',  pct: -8.1 },
  { label: 'Spec Churn',  pct: 0 },
];
const colorFor = (d: number) => d > 0 ? 'bg-success text-black' : d < 0 ? 'bg-danger text-white' : 'bg-paper text-black';
const arrowFor = (d: number) => d > 0 ? '↑' : d < 0 ? '↓' : '→';
const fmt = (d: number) => (d > 0 ? '+' : '') + d.toFixed(1) + '%';
---

<div data-this-component class="w-full bg-paper text-black border-4 border-black divide-y-2 divide-black overflow-hidden">
  {items.map((it) => (
    <div class="flex items-center gap-3 px-3 py-2.5">
      <span class="font-mono text-[10px] uppercase tracking-widest opacity-60 flex-1 truncate">{it.label}</span>
      <span class={`inline-flex items-center gap-1 border-2 border-black px-2 py-0.5 font-black text-[11px] tabular-nums ${colorFor(it.pct)}`}>
        <span class="text-sm leading-none">{arrowFor(it.pct)}</span>
        <span>{fmt(it.pct)}</span>
      </span>
    </div>
  ))}
</div>