Data✨ Premium

Gauge Meter

Half-circle gauge, green to red, with a needle that swings to the value when the gauge appears, then follows every new value.

SVGCSS

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Data has 28 effects, including 1 free. Explore the category →

3 usage examples

Estimated effort of a mountain loop — the gauge at the top of the trail page — Gauge Meter example 1

① Estimated effort of a mountain loop — the gauge at the top of the trail page

WhenA hike page shows the effort gauge next to distance, climb and time. Switching from "Long loop" to "Short loop" brings the needle down from 7 / 10 to 4 / 10 and the word from "Demanding" to "Moderate".
WhyBefore setting off, walkers want to know whether the outing suits them: a needle on a green-to-red dial is understood at a glance, better than a "hard" label lost in the text.
Settingsaria-valuemax="10", data-unit=" / 10", --gmtr-size:170px, dark needle and hub (--gmtr-needle:#17251d, --gmtr-glow:rgba(23,37,29,.12)), track #e6ece8, transparent background. The variant buttons write 7 or 4 into aria-valuenow; in the capture, a click elsewhere in the scene also switches variants.
Fill level of the neighbourhood glass bins — a mini gauge per address — Gauge Meter example 2

② Fill level of the neighbourhood glass bins — a mini gauge per address

WhenThe neighbourhood app lists glass collection points with their distance; each row carries a small gauge and a word ("Almost full", "Available"). The needles settle when the list shows.
WhyPeople pick the bin for their bottles at a glance: green, go; red, try the next one. The code's green-to-red gradient matches that meaning exactly.
SettingsFive roots, one per row: --gmtr-size:84px, track #eef2f6, needle #334155, no halo (--gmtr-glow:transparent), text reduced to 11 px by the scene CSS. Values 92, 58, 15, 80 and 34 in aria-valuenow, aria-label="Bin fill level".
Difficulty of the chosen level — level card in a puzzle game — Gauge Meter example 3

③ Difficulty of the chosen level — level card in a puzzle game

WhenOn the world 1 map, the player taps a level: the card on the right takes its name and the difficulty needle swings to its score out of 10, from 2 for "First steps" to 9 for "The clock".
WhyPlayers hesitate between levels: a needle moving at each choice compares difficulties better than a list of figures, and the gesture recalls a machine dial, in tune with the game.
Settingsaria-valuemax="10", data-unit=" / 10", --gmtr-size:170px, bright colours --gmtr-low:#34d399, --gmtr-mid:#fbbf24, --gmtr-high:#f43f5e, track rgba(196,181,253,.18). Each level button writes its difficulty into aria-valuenow; in the capture, a click outside the buttons moves to the next level.

How it works

The whole drawing sits in a 160 × 100 SVG: a half circle of radius 60 (.gmtr-track), the same half circle painted with a green → yellow → red gradient (.gmtr-fill), a white needle (.gmtr-needle) pivoting around the hub at the centre of the dial, and the value written below it (.gmtr-value). Arc and needle always show the same value: 70% paints 70% of the half circle and sets the needle at 36° (from −90° for 0% to +90° for 100%). The text sits below the hub, so the needle never crosses it.

The value is read from aria-valuenow (between aria-valuemin and aria-valuemax, 0 and 100 by default). By default the text is a percentage in the page format ("70%", "70 %" in French); with data-unit, it shows the raw value followed by the unit, for example aria-valuemax="10" data-unit=" / 10" gives "7 / 10".

Arc and needle stay at zero until the gauge is half visible, then rise over 2 s (ease-out), only once. A new value written to aria-valuenow later makes the needle and arc glide to it. Each gauge has its own gradient id and nothing is declared on window: several gauges live together in the page.

Accessibility

  • Role: role="meter" (a measurement within a known range), with aria-valuetext copied from the displayed text. Name the gauge with aria-label ("Estimated effort", "Bin fill level").
  • Colour and text: the gradient is not the only information, the value is written in figures below the needle.
  • Reduced motion: under prefers-reduced-motion: reduce, no swing and no animated fill; the gauge shows its value as soon as it appears and jumps straight to later values.
  • Reading: a new value is not announced on its own (a gauge is not a live region); if the change matters, announce it in an aria-live region of your own.

Browser compatibility

SVG, CSS transforms on SVG elements, CSS variables and dependency-free JavaScript (about 2.5 KB). Measured on 08/11/2026 in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): arc at 70% and needle at 36° in all three, whole arc with no cut, a gauge further down waiting for the scroll, a new value on the 2nd copy without touching the 1st, 390 px, reduced motion, no error. Versions taken from @mdn/browser-compat-data: IntersectionObserver sets the minimum.

Chrome 51+✓ Full (measured)
Firefox 55+✓ Full (measured)
Safari 12.1+✓ Full (measured in WebKit)
Edge 79+✓ Full (Chromium engine)
iOS Safari 12.2+✓ Not checked on a real device
Android Chrome 51+✓ Full (Chromium engine)

Without IntersectionObserver, the gauge takes its value on load. Without JavaScript, the dial is empty, the needle lies to the left, and the HTML text ("70%") remains readable.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0228-root">
  <div class="gmtr-gauge" role="meter" aria-label="Level" aria-valuemin="0" aria-valuemax="100" aria-valuenow="70">
    <svg class="gmtr-svg" viewBox="0 0 160 100" aria-hidden="true">
      <defs><linearGradient id="gmtr-grad">…</linearGradient></defs>
      <path class="gmtr-track"></path>
      <path class="gmtr-fill"></path>
      <rect class="gmtr-needle"></rect>
      <circle class="gmtr-halo"></circle>
      <circle class="gmtr-hub"></circle>
    </svg>
    <span class="gmtr-value">70%</span>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Value (HTML — aria-valuenow on .gmtr-gauge) 70 Change it at start or in JavaScript (gauge.setAttribute('aria-valuenow', 45)): arc, needle and text follow.
Bounds (HTML — aria-valuemin, aria-valuemax) 0 and 100 A score out of 10: aria-valuemax="10". The needle sits at the matching share of the range.
Displayed unit (HTML — data-unit) absent: percentage ("70%") When present, the text becomes the raw value plus the unit: data-unit=" / 10" → "7 / 10", data-unit=" mph" → "70 mph".
Name for screen readers (HTML — aria-label) Level What the gauge measures: "Estimated effort", "Server load".
Dial colours (CSS — --gmtr-low, --gmtr-mid, --gmtr-high, --gmtr-track) #22c55e · #eab308 · #ef4444 · indigo at 20% The gradient runs left to right. If the top of the scale is good news (full battery), swap --gmtr-low and --gmtr-high.
Needle and hub (CSS — --gmtr-needle, --gmtr-glow) #fff · indigo at 35% On a light background, a dark needle (#1f2937) and a light or transparent halo.
Size (CSS — --gmtr-size) 160px Width of the gauge; the text is 12.5% of that width.
Duration (CSS — --gmtr-duration) 2s Length of the first swing and the next ones.
Background, text and height (CSS — --gmtr-bg, --gmtr-text, --gmtr-height) #0a0a0f · #fff · 300px On a light page: --gmtr-bg:transparent; --gmtr-text:#111827; --gmtr-height:0px.

FAQ

Yes, with .gmtr-value{display:none} in your CSS. Screen readers still hear the value through aria-valuetext. Then write it elsewhere if colour alone is not enough for your visitors.
Set the bounds to your scale (aria-valuemin="0" aria-valuemax="120"), put the measurement in aria-valuenow and the unit in data-unit (" mph"). The number follows the page format, decimal included.
No: a value below the minimum or above the maximum is brought back into the range for the needle and the arc. The text shows the real value when data-unit is used.