Skip to main content
Compendium / Metrics & Telemetry / Gauges / Radial Percent Gauge
#702

Radial Percent Gauge

Full-circle radial gauge with percentage fill and centred numeric readout.

STABLE DE
#svg #gauge #real-content #responsive
Live
64% complete
Spec

Intent

Render a single percentage as a full ring with a large numeric centre — the canonical "progress" radial telemetry.

Acceptance Criteria

  • [ ] 360-degree track + proportional foreground arc
  • [ ] Centred percent label, large + tabular
  • [ ] Theme-aware via tokens
  • [ ] Negative: does NOT animate without prefers-reduced-motion respect

Constraints

  • Pure SVG, no JS
  • Token-driven stroke
// radial-percent-gauge.astro
---
import type { CompendiumMeta } from '../../../data/types';

export const meta: CompendiumMeta = {
  id: 702,
  slug: 'radial-percent-gauge',
  name: 'Radial Percent Gauge',
  category: 'metrics-telemetry',
  subcategory: 'gauges',
  pillar: 'de',
  description: 'Full-circle radial gauge with percentage fill and centred numeric readout.',
  spec: `## Intent
Render a single percentage as a full ring with a large numeric centre — the canonical "progress" radial telemetry.

## Acceptance Criteria
- [ ] 360-degree track + proportional foreground arc
- [ ] Centred percent label, large + tabular
- [ ] Theme-aware via tokens
- [ ] Negative: does NOT animate without prefers-reduced-motion respect

## Constraints
- Pure SVG, no JS
- Token-driven stroke`,
  tags: ['svg', 'gauge', 'real-content', 'responsive'],
  status: 'stable',
  health: { ics: 88, a11y: 'aa', themed: true, animated: false },
};

const value = 64;
const r = 42;
const c = 2 * Math.PI * r;
const dashOffset = c * (1 - value / 100);
---

<div data-this-component class="w-full bg-paper text-black border-4 border-black p-4 flex items-center justify-center overflow-hidden">
  <div class="relative">
    <svg viewBox="0 0 100 100" class="w-32 h-32 block -rotate-90" aria-label={`Value ${value} percent`}>
      <circle cx="50" cy="50" r={r} fill="none" stroke="var(--color-ink)" stroke-width="12" opacity="0.12" />
      <circle cx="50" cy="50" r={r} fill="none" stroke="var(--color-de)" stroke-width="12" stroke-dasharray={c} stroke-dashoffset={dashOffset} stroke-linecap="butt" />
    </svg>
    <div class="absolute inset-0 flex flex-col items-center justify-center">
      <span class="font-black text-2xl tabular-nums leading-none">{value}<span class="text-sm opacity-60">%</span></span>
      <span class="font-mono text-[9px] uppercase tracking-widest opacity-60 mt-1">complete</span>
    </div>
  </div>
</div>