macbetter

Status

Gauge

Show a reading within a known range, and whether it's fine.

Memory Pressure30%
CPU Load72%
Disk Usage94%
import { Gauge, GaugeLabel, GaugeValue } from "macbetter/gauge"

export default function Example() {
  return (
    <div style={{ display: "grid", gap: 20, width: "100%", maxWidth: 320 }}>
      <Gauge variant="level" value={30} low={60} high={85} optimum={0} segments={12}>
        <GaugeLabel>Memory Pressure</GaugeLabel>
        <GaugeValue />
      </Gauge>
      <Gauge variant="level" value={72} low={60} high={85} optimum={0} segments={12}>
        <GaugeLabel>CPU Load</GaugeLabel>
        <GaugeValue />
      </Gauge>
      <Gauge variant="level" value={94} low={60} high={85} optimum={0} segments={12}>
        <GaugeLabel>Disk Usage</GaugeLabel>
        <GaugeValue />
      </Gauge>
    </div>
  )
}

When to use it

Use a gauge for a value that sits in a range and doesn't finish: storage used, battery level, memory pressure, air quality. For a task that's working toward done, use a progress bar.

Set thresholds when the reading can be good or bad. With low, high and optimum, the gauge turns green, yellow or red the way an HTML meter does, so people can tell at a glance whether to act. Without thresholds, it fills in the accent.

Usage

import { Gauge, GaugeLabel, GaugeValue } from "macbetter/gauge"

Put a GaugeLabel and a GaugeValue inside a Gauge; the track is drawn for you.

Thresholds

optimum says which end is good. Below low means lower is better, like CPU load. Above high means higher is better, like a battery. Between them, the middle is best and either end is a warning.

OptimumBelow lowBetweenAbove high
below lowgreenyellowred
above highredyellowgreen
betweenyellowgreenyellow

Level indicator

variant="level" is macOS's discrete level indicator: segments that light up together, all in the color the thresholds give. Set how many with segments.

Linear

The default variant is a capsule that fills, like the storage bar in System Settings.

Macintosh HD182 GB
Battery18%
import { Gauge, GaugeLabel, GaugeValue } from "macbetter/gauge"

export default function Example() {
  return (
    <div style={{ display: "grid", gap: 20, width: "100%", maxWidth: 320 }}>
      <Gauge value={182} max={256} format={{ style: "unit", unit: "gigabyte" }}>
        <GaugeLabel>Macintosh HD</GaugeLabel>
        <GaugeValue />
      </Gauge>
      <Gauge value={18} low={20} high={50} optimum={100}>
        <GaugeLabel>Battery</GaugeLabel>
        <GaugeValue />
      </Gauge>
    </div>
  )
}

Circular

variant="circular" is the open ring from watchOS complications and iOS widgets: 270 degrees, with the value in the middle and the label below.

84%Battery
7.4KSteps
92%Storage
import { Gauge, GaugeLabel, GaugeValue } from "macbetter/gauge"

export default function Example() {
  return (
    <div style={{ display: "flex", alignItems: "flex-start", gap: 32 }}>
      <Gauge variant="circular" size="sm" value={84} low={20} high={50} optimum={100}>
        <GaugeValue />
        <GaugeLabel>Battery</GaugeLabel>
      </Gauge>
      <Gauge variant="circular" value={7400} max={10000} format={{ notation: "compact" }}>
        <GaugeValue />
        <GaugeLabel>Steps</GaugeLabel>
      </Gauge>
      <Gauge variant="circular" size="lg" value={92} low={70} high={90} optimum={0}>
        <GaugeValue />
        <GaugeLabel>Storage</GaugeLabel>
      </Gauge>
    </div>
  )
}

Gradient

gradient paints the whole ring from green to red, following its curve, and marks the value with a knob. Use it for a scale, like air quality or UV index, where where you are on the scale matters more than how full it is. The gradient runs from the good end to the bad one, so it flips when higher is better.

42Air Quality
7UV Index
import { Gauge, GaugeLabel, GaugeValue } from "macbetter/gauge"

export default function Example() {
  return (
    <div style={{ display: "flex", alignItems: "flex-start", gap: 32 }}>
      <Gauge variant="circular" gradient value={42} max={300} low={50} high={150} optimum={0} format={{ style: "decimal" }}>
        <GaugeValue />
        <GaugeLabel>Air Quality</GaugeLabel>
      </Gauge>
      <Gauge variant="circular" gradient size="lg" value={7} max={11} low={3} high={6} optimum={0} format={{ style: "decimal" }}>
        <GaugeValue />
        <GaugeLabel>UV Index</GaugeLabel>
      </Gauge>
    </div>
  )
}

Platform behavior

Level indicators are 14 points tall on macOS and 18 on iOS and iPadOS; circular gauges are 64 and 72 points at the default size. The level indicator is a Mac control: on iOS, prefer the linear or circular gauge.

Linear and level gauges fill from the right in a right-to-left layout. The circular gauge keeps running clockwise.

System yellow is under 3:1 against a white page, so in light mode a suboptimal reading gets a darker edge of the same yellow. The hue doesn't change, and dark mode needs no edge.

Accessibility

  • A gauge is a meter, named by GaugeLabel or aria-label, and reads its value. The visible value is hidden from screen readers so it isn't read twice.
  • Color is never the only signal: the value is always read, and should be shown. Add getValueLabel when the number needs words, like "Moderate".
  • The circular gauge's ring and the level indicator's segments are hidden from assistive technology.

API

PropTypeDefaultDescription
valuenumber—The reading.
minnumber0The start of the range.
maxnumber100The end of the range.
variant"linear" | "level" | "circular""linear"How it's drawn.
size"sm" | "md" | "lg""md"Thickness, or the ring's diameter.
lownumber—Where the low region ends.
highnumber—Where the high region starts.
optimumnumber—The best value, which says which region is good.
segmentsnumber10How many segments a level indicator draws.
gradientboolean—Paints a circular gauge's ring as a gradient with a marker.
formatIntl.NumberFormatOptions | (value) => string—How the value reads.

GaugeLabel and GaugeValue take ui-sdk's MeterLabel and MeterValue props.

Attribute or variableOnDescription
data-variant, data-size.mb-gaugeThe props.
data-level.mb-gaugeoptimum, suboptimal or critical, when thresholds are set.
data-lit.mb-gauge-segmentA lit segment.
--meter-value.mb-gaugeThe reading as a percentage, from ui-sdk.
--mb-gauge-good, --mb-gauge-fair, --mb-gauge-poor.mb-gaugeThe three level colors.
--mb-gauge-edge.mb-gaugeThe edge drawn around a reading. Transparent except for a suboptimal reading in light mode.
--mb-gauge-ringany ancestorThe color that cuts the gradient marker out of the ring. Defaults to --mb-bg.