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>