Meter
FeedbackLocal guide ↗
import { Meter } from "bits-ui" Disk usage thresholds
A capacity reading changes colour as healthy, high and critical thresholds are crossed
Workspace disk
Healthy usage
312 GB / 500 GB
<script lang="ts">
import { Meter, useId } from 'bits-ui';
const labelId = useId();
const capacity = 500;
let value = $state(312);
const percentage = $derived((value / capacity) * 100);
const tone = $derived(
value >= 450 ? 'bg-ink-50' : value >= 350 ? 'bg-accent-500' : 'bg-brand-500'
);
const level = $derived(value >= 450 ? 'Critical' : value >= 350 ? 'High' : 'Healthy');
</script>
<div class="grid gap-4">
<div class="flex items-end justify-between gap-4">
<div>
<p id={labelId} class="text-sm font-medium text-ink-50">Workspace disk</p>
<p class="muted mt-1 text-xs">{level} usage</p>
</div>
<p class="font-mono text-sm text-ink-200">{value} GB / {capacity} GB</p>
</div>
<Meter.Root
aria-labelledby={labelId}
aria-valuetext={`${value} gigabytes used out of ${capacity}`}
{value}
max={capacity}
class="h-3 w-full overflow-hidden rounded-full border border-ink-700 bg-ink-900"
>
<div
class="h-full w-full rounded-full transition-all duration-300 {tone}"
style={`transform: translateX(-${100 - percentage}%)`}
></div>
</Meter.Root>
<div class="flex flex-wrap gap-2">
<button class="btn btn-sm" onclick={() => (value = 312)}>Healthy · 312 GB</button>
<button class="btn btn-sm" onclick={() => (value = 390)}>High · 390 GB</button>
<button class="btn btn-sm" onclick={() => (value = 468)}>Critical · 468 GB</button>
</div>
</div>
Battery reserve
A fluctuating measurement with a domain-specific accessible value
Battery reserve
Estimated runtime at the current load
Known range: 0–24 hours
<script lang="ts">
import { Meter, useId } from 'bits-ui';
const labelId = useId();
const max = 24;
let hours = $state(7.5);
const percentage = $derived((hours / max) * 100);
const tone = $derived(
hours <= 4 ? 'bg-accent-500' : hours <= 10 ? 'bg-ink-200' : 'bg-brand-500'
);
function adjust(delta: number) {
hours = Math.max(0, Math.min(max, hours + delta));
}
</script>
<div class="grid gap-4">
<div class="flex items-center justify-between gap-4">
<div>
<p id={labelId} class="text-sm font-medium text-ink-50">Battery reserve</p>
<p class="muted mt-1 text-xs">Estimated runtime at the current load</p>
</div>
<span class="chip">{hours.toFixed(1)} h</span>
</div>
<Meter.Root
aria-labelledby={labelId}
aria-valuetext={`${hours.toFixed(1)} hours remaining`}
value={hours}
min={0}
{max}
class="h-3 w-full overflow-hidden rounded-full border border-ink-700 bg-ink-900"
>
<div
class="h-full w-full rounded-full transition-all duration-300 {tone}"
style={`transform: translateX(-${100 - percentage}%)`}
></div>
</Meter.Root>
<div class="flex flex-wrap items-center gap-2">
<button class="btn btn-sm" onclick={() => adjust(-2.5)} disabled={hours === 0}>Drain 2.5 h</button>
<button class="btn btn-sm" onclick={() => adjust(2.5)} disabled={hours === max}>Charge 2.5 h</button>
<span class="muted text-xs">Known range: 0–24 hours</span>
</div>
</div>
A meter reports a current measurement within a known range, so its value may move in either direction. Progress instead communicates advancement toward task completion and ordinarily moves forward. For units that are clearer than a percentage, provide aria-valuetext (for example, gigabytes used or hours remaining) and connect the visible label with aria-labelledby.