Meter
A level meter milled into the chassis — zone colors are painted into the channel and a shutter covers what the value hasn't reached.
@emboss/meter
Master
Installation
pnpm dlx shadcn@latest add @emboss/meterUsage
import { Meter } from "@/components/ui/meter";
export function Example() {
return <Meter value={64} aria-label="Master level" />;
}API reference
Meter
Read-only meter semantics from the primitive; label with aria-label or the MeterLabel part.
| Prop | Type | Default | Description |
|---|---|---|---|
| value | number | — | Current reading. |
| min / max | number / number | 0 / 100 | Range of the scale. |
| warnAt / dangerAt | number / number | 0.7 / 0.9 | Zone boundaries as fractions of the range. |
MeterLabel / MeterValue
Optional labelled readout parts, wired to the meter by the primitive.
Source
View source — meter.tsxHide source — meter.tsx
"use client";
import { Meter as BaseMeter } from "@base-ui/react/meter";
import { cn } from "@/lib/utils";
export type MeterProps = React.ComponentProps<typeof BaseMeter.Root> & {
/** Where the warning zone begins, as a fraction of the range. */
warnAt?: number;
/** Where the danger zone begins, as a fraction of the range. */
dangerAt?: number;
};
/**
* A level meter milled into the chassis. The full zone strip — safe, warning,
* danger — is painted into the channel and a shutter covers whatever the
* current value hasn't reached, so the reading is position plus color.
*
* @example
* <Meter value={-6.2} min={-60} max={0} aria-label="Master level" />
*/
function Meter({
className,
children,
warnAt = 0.7,
dangerAt = 0.9,
value,
min = 0,
max = 100,
...props
}: MeterProps) {
const fraction = Math.min(1, Math.max(0, (value - min) / (max - min || 1)));
return (
<BaseMeter.Root
data-slot="meter"
value={value}
min={min}
max={max}
{...props}
>
<BaseMeter.Track
data-slot="meter-track"
className={cn(
"relative block h-3 w-full overflow-hidden rounded-sm shadow-deboss-2",
className,
)}
style={{
background: `linear-gradient(to right, var(--positive) 0 ${warnAt * 100}%, var(--warning) ${warnAt * 100}% ${dangerAt * 100}%, var(--danger) ${dangerAt * 100}% 100%)`,
}}
>
<BaseMeter.Indicator
data-slot="meter-indicator"
className="block h-full"
/>
{/* The shutter: covers the span the value has not reached. */}
<span
aria-hidden
className="absolute inset-y-0 right-0 bg-well-deep transition-[left] duration-(--duration-settle) ease-(--ease-settle)"
style={{ left: `${fraction * 100}%` }}
/>
</BaseMeter.Track>
{children}
</BaseMeter.Root>
);
}
function MeterLabel({
className,
...props
}: React.ComponentProps<typeof BaseMeter.Label>) {
return (
<BaseMeter.Label
data-slot="meter-label"
className={cn("text-sm font-medium text-ink", className)}
{...props}
/>
);
}
function MeterValue({
className,
...props
}: React.ComponentProps<typeof BaseMeter.Value>) {
return (
<BaseMeter.Value
data-slot="meter-value"
className={cn("font-mono text-sm text-ink-muted tabular-nums", className)}
{...props}
/>
);
}
export { Meter, MeterLabel, MeterValue };