- Accordion
- Alert
- Alert Dialog
- Avatar
- Badge
- Button
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Circular Progress
- Collapsible
- Compare Slider
- Dialog
- Dropdown Menu
- Gauge
- Input
- Label
- Marquee
- Navigation Menu
- Number Field
- Pagination
- Popover
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Tooltip
Demos
A full ring with the value as a percentage.
"use client"
import * as React from "react"
import { GaugeCombined } from "@workspace/ui/components/gauge"
export function GaugeDemo() {
const [value, setValue] = React.useState(20)
React.useEffect(() => {
const timer = setTimeout(() => setValue(72), 500)
return () => clearTimeout(timer)
}, [])
return <GaugeCombined value={value} aria-label="Health score" />
}
Usage
Use a gauge to show a single measurement against a fixed range: a health score, sleep quality, recovery. It reads as a reading, not a task, so use a progress bar for uploads and other work in flight.
Import it from @workspace/ui/components/gauge.
For the common case, GaugeCombined renders the indicator, track, range and value text for you.
Anatomy
- Gauge — The root. Holds the value and geometry, and has the
meterrole. - GaugeIndicator — The SVG that draws the ring. Put GaugeTrack and GaugeRange inside it.
- GaugeTrack — Every segment, in a muted colour.
- GaugeRange — The filled segments, up to the current value.
- GaugeValueText — The text centred over the ring. Defaults to a percentage.
- GaugeLabel — Names the measurement. Read by screen readers.
Notes
- Without a GaugeLabel, give the root an
aria-label. - GaugeValueText is centred over its nearest positioned parent. If you place a GaugeLabel below the ring, wrap the indicator and value text in a
relativeelement so the text stays centred on the ring. - Pass
getValueTextto change the text read by screen readers and shown by default. Pass children to GaugeValueText to change only what is shown. - Colour the fill with a text colour class on GaugeRange, for example
text-chart-2. Segments usecurrentColor. - The gauge lowers
segmentswhen they would not fit around the ring at the giventhicknessandgap.
Examples
With label
A GaugeLabel below the ring.
"use client"
import {
Gauge,
GaugeIndicator,
GaugeLabel,
GaugeRange,
GaugeTrack,
GaugeValueText,
} from "@workspace/ui/components/gauge"
export function GaugeWithLabel() {
return (
<Gauge value={84} size={160} thickness={10} gap={14} className="gap-3">
<div className="relative">
<GaugeIndicator>
<GaugeTrack />
<GaugeRange />
</GaugeIndicator>
<GaugeValueText />
</div>
<GaugeLabel>Sleep quality</GaugeLabel>
</Gauge>
)
}
Arc
Set startAngle and endAngle to draw part of a ring. Angles are in degrees, with 0 at the top, increasing clockwise.
"use client"
import {
Gauge,
GaugeIndicator,
GaugeRange,
GaugeTrack,
GaugeValueText,
} from "@workspace/ui/components/gauge"
export function GaugeArc() {
return (
<Gauge
value={58}
startAngle={-120}
endAngle={120}
segments={40}
aria-label="Recovery"
>
<GaugeIndicator>
<GaugeTrack />
<GaugeRange />
</GaugeIndicator>
<GaugeValueText />
</Gauge>
)
}
Custom value
Set min and max for a range that is not 0–100, and pass children to GaugeValueText to show a unit and caption.
"use client"
import {
Gauge,
GaugeIndicator,
GaugeRange,
GaugeTrack,
GaugeValueText,
} from "@workspace/ui/components/gauge"
export function GaugeCustomValue() {
return (
<Gauge
value={38}
min={18}
max={90}
getValueText={(value) => `${value} years`}
aria-label="Biological age"
>
<GaugeIndicator>
<GaugeTrack />
<GaugeRange className="text-chart-2" />
</GaugeIndicator>
<GaugeValueText className="flex-col gap-0.5">
<span className="text-3xl font-medium">38</span>
<span className="text-xs text-muted-foreground">Biological age</span>
</GaugeValueText>
</Gauge>
)
}
Sizes
Change size, and lower segments and tickInnerRadius on small gauges so the ticks stay readable.
"use client"
import { GaugeCombined } from "@workspace/ui/components/gauge"
export function GaugeSizes() {
return (
<div className="flex flex-wrap items-center justify-center gap-6">
<GaugeCombined
value={45}
size={96}
segments={30}
tickInnerRadius={30}
className="[&>div]:text-base"
aria-label="Small gauge"
/>
<GaugeCombined
value={45}
size={140}
segments={45}
className="[&>div]:text-xl"
aria-label="Medium gauge"
/>
<GaugeCombined value={45} aria-label="Large gauge" />
</div>
)
}
Indeterminate
Set value={null} when there is no reading yet. Only the track is drawn.
"use client"
import { GaugeCombined } from "@workspace/ui/components/gauge"
export function GaugeIndeterminate() {
return <GaugeCombined value={null} aria-label="Waiting for results" />
}
Props
These are the props you set most often. Unlisted props pass through to the underlying element.
Gauge
| Prop | Type | Default | Description |
|---|---|---|---|
value | number or null | null | Current value. null is indeterminate. Clamped to min–max. |
min | number | 0 | Lowest value. |
max | number | 100 | Highest value. |
getValueText | (value, min, max) => string | Percentage | Text for screen readers and the default GaugeValueText. |
size | number | 200 | Width and height in pixels. |
thickness | number | 2 | Stroke width of each segment. |
gap | number | 4 | Minimum space between segments. |
segments | number | 60 | Number of segments. |
startAngle | number | 0 | Where the ring starts, in degrees. |
endAngle | number | 360 | Where the ring ends, in degrees. |
tickInnerRadius | number | Radius − 24 | Inner end of each segment. |
tickOuterRadius | number | Radius | Outer end of each segment. |
className | string | — | Classes merged onto the root. |
Data attributes
The root, GaugeIndicator and GaugeRange set data-state to indeterminate, loading or complete, so you can style each state, for example data-[state=complete]:text-chart-2.