Spec version v0.15.0

Gauge Chart

Purpose

A Gauge chart shows a single numeric value positioned within a bounded, meaningful range on a 180-degree semi-circular arc. Use it when the reader needs to answer one question at a glance: where does this value sit within a known range? Common cases include capacity utilisation, percentage of target, and progress against a hard operational limit.

Do NOT use a Gauge when the range is unbounded or arbitrary (e.g., active user counts) — use a KPI tile instead. Do NOT use a Gauge to compare multiple values across categories — use a Bar chart. Do NOT use a Gauge when the trend over time is the primary takeaway — use a Line chart.

Anatomy

A Gauge chart is composed of the following parts:

  • Title (required at md and lg density, optional at sm): the headline label placed above the chart. Wraps to a second line before truncating with ellipsis.
  • Subtitle (optional): a single context line directly beneath the title. Does not wrap.
  • Arc track (required): the full 180-degree background arc from min (left endpoint, 9 o'clock) to max (right endpoint, 3 o'clock), rendered in a muted colour to show the available range.
  • Value fill (required): a filled arc drawn clockwise from the min endpoint to the angle that corresponds to the current value. The fill colour is --force-color-chart-1 by default and changes to a status colour when threshold zones are configured.
  • Centre KPI (required at md and lg): the large numeric value displayed inside the arc bowl, typically rendered as a percentage or raw value on the first line and a short unit label on the second (e.g., "78%" over "of capacity").
  • Min label (shown at md and lg): the formatted value at the left arc endpoint.
  • Max label (shown at md and lg): the formatted value at the right arc endpoint.
  • Threshold ticks (optional): short tick marks on the arc at meaningful threshold boundaries. Required when threshold zones are configured.
  • Detail KPIs (optional): an external panel to the right of the arc displaying one or more secondary metrics (e.g., "HEADROOM: 2.2 GB before scale-up trigger"). Controlled by the headlineMetric prop.
  • Action menu (optional): a three-dot icon in the top-right corner of the widget, providing Export and Refresh actions.
  • Tooltip (optional, default on): anchored above the value position on the arc. Shows the raw value, the percentage of the range, and the zone name when threshold zones are configured.
  • Legend (conditional): shown only in the threshold-zones variant. Lists zone names with their colour swatches. Defaults to 'none' for all other variants.

The Gauge has no axes. The arc span is always 180 degrees. The arc track always starts at the min value and ends at the max value.

When to Use

Use a Gauge when:

  • The value lives within a bounded, meaningful range — 0 to 100%, 0 to a capacity limit, 0 to a hard target.
  • The position within the range is the takeaway, not the absolute value alone.
  • The reader needs to see "how close to the limit, target, or capacity" at a glance.
  • Exactly one value is being shown.

Do NOT use a Gauge when:

  • The range is unbounded or arbitrary (e.g., active user count, request count). Use a KPI tile.
  • The reader needs to compare multiple values across categories. Use a Bar chart.
  • The value changes over time and the trend is the takeaway. Use a Line chart.
  • The value has a categorical breakdown. Use a Donut chart.
  • The container is narrower than 160px. Use a Progress bar instead.

Data Requirements

Requirement Constraint Behaviour at the limit
Required fields value (number), min (number), max (number) Missing any field → Empty state with explanation
Accepted data types Numbers only. min must be less than max Strings or mixed types are rejected at design time
Minimum data points 1 value No value → Empty state. Do NOT render a zero-filled arc — a zero fill is visually indistinguishable from an actual zero reading
Maximum data points 1 value plus an optional target Additional values are ignored. Multiple series → Error state with redirect to Bar chart
Null / missing value Render the Empty state Never render a zero-filled arc as a fallback
Negative values Permitted only when min is negative. Values outside [min, max] are clamped An out-of-range value triggers the Error state with a banner explaining the clamp
Sort order Not applicable — single value Caller-provided order is ignored
Aggregation None. Caller provides the value at the desired granularity Multiple readings in the payload → Error state

Configuration

Content

Prop Type Default Purpose
title string required Headline label above the chart. Wraps to two lines, then truncates with ellipsis.
subtitle string? undefined Optional single-line context beneath the title.
headlineMetric object? undefined Optional external KPI panel alongside the gauge. Most cases are served by the centre KPI alone; use this only when a secondary metric (headroom, delta, burn rate) genuinely adds value.

Data

Prop Type Default Purpose
data object required A single object { value, min, max, target? }. Schema defined in Data Requirements above.
referenceLines object[]? [] Threshold zone definitions for the threshold-zones and target-zone variants. Each zone: `{ from, to, color?

Visual

Prop Type Default Purpose
variant 'standard' | 'threshold-zones' | 'with-target' | 'mini' | 'kpi-with-delta' | 'target-zone' 'standard' Approved variants documented in the Variants section.
colorMapping object? system Override the arc fill colour. The threshold-zones variant uses status tokens (success / warning / danger) by default.
density 'sm' | 'md' | 'lg' 'md' Controls arc stroke width, label visibility, and KPI size. See the Sizing section.
theme 'light' | 'dark' | 'auto' 'auto' Overrides the dashboard-level theme.

Behavioural

Prop Type Default Purpose
legend 'bottom' | 'right' | 'none' 'none' Legend is hidden by default. Required when threshold zones are named.
tooltip boolean true Hover or focus reveals a tooltip at the value position.
onMarkClick function? undefined Gauges are rarely clickable. Provide only when drill-down is genuinely useful. When set, the gauge becomes focusable and clicking fires the handler with the current reading.
exportable boolean true Whether the action menu exposes an Export action.

Variants

standard (default)

A single-colour filled arc from the min endpoint to the value position. The arc track shows the full range in a muted background colour. The centre KPI displays the value. Min and max labels appear at the arc endpoints at md and lg density.

Use when the question is "where on the scale?" and no zone information is relevant.

threshold-zones

The arc is divided into two or more colour bands at meaningful threshold boundaries (for example, Safe: 0–70%, Warning: 70–90%, Critical: 90–100%). The value fill adopts the colour of the zone it lands in. Short tick marks on the arc delineate each zone boundary. A legend lists zone names.

Use when the reader needs to see both the current position and which zone it falls into. The Figma audit recommended this variant for all status-driven readings (capacity, health, SLA compliance) to replace ad-hoc red/green fills.

Status colour assignments: Safe → --force-color-chart-3 (green), Warning → --force-color-chart-4 (orange), Critical → --force-color-chart-5 (cranberry). Zone names and colour labels always appear together — colour alone is never the sole signal.

with-target

The standard arc plus a notch or needle marking the target value position on the arc. The target marker is labelled (e.g., "Target 80"). Use when the question is "are we hitting our target?" rather than "where on the scale?"

A target field must be present in the data prop. If the target is outside [min, max], the chart renders the Error state.

mini

A compact gauge with no centre KPI, no min/max labels, and no arc track labels. Tooltip only. Used inside table cells, status columns, or as a sub-element of a KPI tile where vertical space is at a premium. Always rendered at sm density regardless of the density prop.

kpi-with-delta

A standard arc paired with an external KPI panel showing the current reading, a delta badge (e.g., "+1.6 pp w/w"), and optional secondary metrics such as a burn rate or SLO target. Use when the takeaway is both the current position on the arc and how it has changed.

The external KPI panel is rendered to the right of the arc at md and lg density. At sm density it collapses to a tooltip.

target-zone

A single highlighted band on the arc showing the acceptable range (e.g., 18–24°C). The arc fill outside the band shifts to the warning status colour. A legend entry labels the target zone. Use when the acceptable window is a range rather than a single target value.

States

Default (happy path)

The arc is fully rendered with the value fill drawn clockwise to the current value position. The centre KPI shows the value and unit label. On first render, the fill animates from 0 to the value position over --force-duration-moderate (300ms) using --force-easing-standard. On value update, the fill transitions to the new position over --force-duration-fast (150ms).

Loading

Data is being fetched. Render the arc track at --force-opacity-subtle (0.7) opacity. In place of the centre KPI, render a skeleton block (two lines: a wider primary and a narrower secondary). The title and header remain fully visible. Show a "Loading…" label in the top-right corner. Do NOT show a spinner in the arc bowl — the reduced-opacity track communicates "in progress" without falsely suggesting a zero reading.

Empty

No reading is available (value is null or absent). Render the full arc track without a fill. Show a text message inside the arc bowl explaining why ("No reading available" and a short action hint). Do NOT render a zero-filled arc — this would imply a real reading at the minimum.

Error

Data fetch failed. Render the full arc track without a fill and overlay an error icon, message ("Could not load"), and a Retry button inside the bowl. Never silently fall back to Empty. Use --force-color-icon-destructive for the icon.

No Permission

The viewer cannot see the underlying data. Render the full arc track without a fill and overlay a lock icon and explanation ("You do not have access to this data. Ask an administrator for access."). Do not reveal any value — not even a greyed-out fill.

Partial Data / Stale

The range is known but the current reading is stale (e.g., the monitoring agent has not reported recently). Render the last known value fill at --force-opacity-subtle (0.7) opacity. Add a banner beneath the title stating when the reading was captured ("Last reading captured 12 minutes ago, may be stale"). Label the centre KPI with "(stale)" to prevent misreading.

Interaction

Hover and Focus

On pointer hover or keyboard focus, the arc fill brightens (lightens one step toward the palette midpoint). A tooltip appears anchored 12px above the outer edge of the arc at the value position. On touch, a tap opens the tooltip.

Tooltip

The tooltip is anchored to the value position on the arc (not cursor-following). It shows:

  • The raw value with its unit (e.g., "7.8 GB")
  • The percentage of range (e.g., "78% of capacity")
  • The zone name, when threshold zones are configured (e.g., "Warning zone")

Click

No-op by default. When onMarkClick is provided, the entire gauge becomes focusable and clicking or pressing Enter fires the handler with the current reading. Use only when drill-down is meaningful and the user expects a navigation or filter action.

Legend Interaction (threshold-zones variant)

Clicking a zone name in the legend highlights that band on the arc, dimming all other bands to --force-opacity-subtle. Useful for drawing attention to a specific zone during a presentation. Clicking again removes the highlight.

Zoom and Pan

Not applicable. Gauges are not zoomable or pannable.

Cross-Filter

Not applicable. Gauges are single-value and do not participate in dashboard cross-filter.

Keyboard Navigation

  • Tab focuses the gauge widget container.
  • On focus, the tooltip reveals automatically without further input.
  • Enter fires onMarkClick if provided; otherwise no-op.
  • Escape moves focus to the next widget in the dashboard.
  • Arrow keys have no effect — there is only one value, nothing to step through.

Accessibility

  • Colour contrast: Arc fill, arc track, and centre KPI text all meet WCAG 2.2 AA against the chart background. Status-zone colours (success / warning / danger) resolve to compliant pairs by default.
  • Colour-blind safety: Threshold zones use the Force UI status palette supplemented with secondary cues — a tick mark at each zone boundary plus a text label in the tooltip and legend. Colour alone is never the sole signal of zone status.
  • Screen reader: The gauge container carries an accessible name derived from title. A summary string is exposed to assistive technology: "<title>, <value> <unit>, <zone name if applicable>". A data-table fallback is reachable via a keyboard shortcut from within the gauge focus region.
  • Keyboard reachability: Tab moves focus to the gauge. The tooltip reveals on focus.
  • Focus ring: A visible focus ring using --force-shadow-focus-ring appears on the gauge container on :focus-visible. Distinct from the hover state.
  • Reduced motion: When prefers-reduced-motion: reduce is set, the fill animation on initial render and value update is suppressed. The new value snaps into position immediately.
  • Text scaling: The component reflows without clipping up to 200% text size. The centre KPI shrinks to the next smaller scale step before truncating. Min/max endpoint labels collapse to tooltip-only when space is insufficient.

Sizing

Density Width range Arc stroke width What is shown
sm < 320px 8px Arc track and fill only. No centre KPI, no endpoint labels. Tooltip on tap. Effectively the mini variant regardless of variant prop.
md 320–599px 12px Centre KPI value and unit. Min/max labels at arc endpoints. Threshold zone tick marks (no named legend).
lg ≥ 600px 16px Centre KPI with value, unit, and percentage. Min/max labels with units. Threshold zone tick marks with a named legend when variant: 'threshold-zones'.

At all densities, the arc aspect ratio is fixed: the plot area is square and the arc occupies the upper half, so the component height equals approximately 60% of its width (half-circle plus endpoint labels and padding).

Below 160px wide, drop the gauge entirely and substitute a Progress bar component.

Guidance

Do

  • Always supply a bounded, meaningful min and max. The arc position is only informative when the range has a real-world interpretation (0–100% capacity, 0 to allocated GB). A gauge with an invented range misleads the reader.
  • Use threshold zones for any status-driven reading (capacity, health, SLA). The zones turn the arc into a "where am I relative to the danger zone?" answer, which is more useful than a single colour.
  • Always pair status colours with text labels. A red fill with no caption tells the reader something is wrong but not what or why. Use the threshold-zones variant and name each zone.
  • Use one canonical gauge style (semi-circular) throughout the product. Do not mix semi-circular gauges, radial gauges, and traffic lights in the same dashboard — the reader learns the grammar once and applies it everywhere.

Don't

  • Do NOT use a gauge for unbounded values (active user counts, total requests, cumulative bytes transferred). The arc position becomes meaningless when the upper bound is arbitrary. Use a KPI tile.
  • Do NOT render a zero-filled arc for missing or null data. A zero fill implies a real reading at the minimum. Show the Empty state instead.
  • Do NOT place multiple gauges for the same metric when a single gauge at a wider width would suffice. Gauge grids work for comparing the same metric across peers (e.g., disk capacity across hosts), but not for comparing unrelated metrics — use a bar chart for that.
  • Do NOT use the mini variant as the only representation of a critical metric. The mini gauge has no labels and no KPI; it is a supporting visual element, not a primary answer surface.

Token Usage

Arc track

  • Fill: --force-color-bg-muted (neutral.100)
  • Stroke: none

Arc fill — standard variant

  • Fill: --force-color-chart-1 (indigo.500)
  • Hover brighten: --force-color-chart-1 at --force-opacity-subtle overlay on the fill (implementation-level effect)

Arc fill — threshold-zones variant

  • Safe zone fill: --force-color-chart-3 (green.500)
  • Warning zone fill: --force-color-chart-4 (orange.500)
  • Critical / danger zone fill: --force-color-chart-5 (cranberry.500)
  • Tick marks at zone boundaries: --force-color-bg-surface (white), 2px wide, full arc stroke height

Target marker (with-target variant)

  • Notch fill: --force-color-text-primary
  • Notch width: 3px, full arc stroke height
  • Target label: --force-font-size-xs, --force-color-text-secondary

Target zone highlight (target-zone variant)

  • Highlighted band fill: --force-color-chart-6 (blue.500) at 40% opacity over the track
  • Segment outside the target zone: --force-color-chart-4 (orange.500) fill
  • Zone label: --force-font-size-xs, --force-color-text-secondary

Centre KPI

  • Primary value text: --force-font-size-3xl (lg), --force-font-size-2xl (md) — font weight --force-font-weight-semibold
  • Unit label: --force-font-size-sm, --force-font-weight-regular, --force-color-text-secondary
  • Loading skeleton: --force-color-bg-muted, animated shimmer

Status badge (threshold-zones tooltip and legend)

  • Background: matches zone fill (success / warning / danger status token)
  • Text: --force-color-text-on-primary
  • Border radius: --force-radius-badge

Min / max labels

  • Text: --force-font-size-xs, --force-color-text-secondary
  • Alignment: left-aligned (min) and right-aligned (max) below the arc endpoints

Title and subtitle

  • Title: --force-font-size-md, --force-font-weight-medium, --force-color-text-primary
  • Subtitle: --force-font-size-sm, --force-font-weight-regular, --force-color-text-secondary

Tooltip

  • Background: --force-color-bg-surface-overlay
  • Border: --force-color-border-default
  • Shadow: --force-shadow-md
  • Text: --force-font-size-sm, --force-color-text-primary
  • Secondary rows: --force-color-text-secondary

Stale / partial data

  • Arc fill opacity: --force-opacity-subtle (0.7)
  • Banner background: --force-color-bg-warning-subtle
  • Banner text: --force-color-text-warning, --force-font-size-xs

Focus ring

  • Box shadow: --force-shadow-focus-ring
  • Applied via :focus-visible on the gauge container

Animation

  • Initial fill: --force-duration-moderate (300ms), --force-easing-standard
  • Value update: --force-duration-fast (150ms), --force-easing-standard
  • Suppressed when prefers-reduced-motion: reduce

Related Components

Component Relationship When to redirect
KPI tile Single-value alternative When the value has no bounded range, or when the absolute number is the takeaway rather than its position in a range
Progress bar Inline linear alternative When the container is too narrow for a usable gauge (below 160px), or when a compact inline indicator is sufficient
Donut chart (goal-progress variant) Alternative progress metaphor When the visual brief is "filling toward a goal" rather than "where on a known scale"
Bar chart Multi-value alternative When the same metric must be compared across multiple categories or peers
Line chart Time-series alternative When the trend over time is the takeaway rather than the current position