Skip to content
WANCRAFT

G.57Data & Feedback

Radial Gauge

A semi or three-quarter dial whose needle springs between values, with labelled threshold zones.

NewReactMotionSVGTailwindintermediate

Overview

Radial Gauge draws an engineered dial in SVG: a track, coloured threshold zones, major and minor ticks with labels, a filled value arc and a needle. Updates never restart from the minimum — a Motion spring carries the needle and arc from the previous value to the new one, and the readout counts along with it, all written straight to the DOM. Each zone has a text label (“Elevated”, “Critical”) shown as a status chip, so meaning never relies on colour. The root is a real role="meter" with aria-valuenow, min, max and a value text that includes the unit and status.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/radial-gauge.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/radial-gauge.json

Method 02 · Copy and paste

  1. 1. Install the dependencies below.
  2. 2. Copy the source from the Code tab into components/ui/radial-gauge.tsx.
  3. 3. Import it and adjust props.
npm install motion
Dependencies
motion
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { RadialGauge, type GaugeThreshold } from "@/components/ui/radial-gauge";

export function RadialGaugeExample() {
  const thresholds: GaugeThreshold[] = [
    { value: 0, color: "#5FCB98", label: "Normal" },
    { value: 60, color: "#F5B544", label: "Elevated" },
    { value: 85, color: "#FF7448", label: "Critical" },
  ];

  return (
    <RadialGauge label="CPU load" value={64} thresholds={thresholds} />
  );
}

03Props

PropTypeDefaultDescription
valuenumber—Current value (required). Changes spring from the previous value.
labelstring—Accessible name and caption (required).
minnumber0Lower bound.
maxnumber100Upper bound.
arc"semi" | "three-quarter""three-quarter"Sweep of the dial (180° or 270°).
indicator"needle" | "arc" | "both""both"Needle, filled value arc, or both.
thresholds{ value: number; color: string; label: string }[][]Zones starting at each value; the zone's label is shown as the status.
ticksnumber5Major intervals; minor ticks are added between them.
tickLabelsbooleantruePrint values at the major ticks.
unitstring""Unit after the readout and in the value text.
format(value: number) => string—Formats readout, tick labels and aria-valuetext (default: whole numbers).
spring{ stiffness: number; damping: number; mass: number }{ stiffness: 120, damping: 16, mass: 1 }Spring for the needle, arc and readout.
accentstring"#FF7448"Needle colour; value arc colour when there are no thresholds.
sizenumber280Maximum width in px; scales down with its container.

04Features

  • 01Semicircle or three-quarter dial in SVG
  • 02Needle, value arc and readout spring from the previous value — never from zero
  • 03Threshold zones with text labels; the value arc takes the zone colour
  • 04Major and minor ticks with optional labels
  • 05Custom formatter and unit
  • 06Animated values written straight to the DOM — no React render per frame
motion · springinput · click

05Accessibility

  • The root is role="meter" with aria-valuenow, aria-valuemin, aria-valuemax and an aria-valuetext such as “72 %, Elevated”.
  • The caption is the meter's accessible name (aria-labelledby).
  • Status is shown as text in a chip alongside the colour dot, never by colour alone.
  • With prefers-reduced-motion the needle jumps to new values instead of springing.