Installation
npx shadcn@latest add @pixeldosa/confidence-meterRequires `cn` at `@/lib/utils`. Has no client-side behaviour (no state, effects, or event handlers), so it carries no `"use client"` directive and can render on the server.
Usage
import { ConfidenceMeter } from "@/components/ui/confidence-meter";
<ConfidenceMeter confidence="medium" provenance="acme-robotics.com" />
confidence is a three-tier enum, never a raw percentage — a fabricated number would
claim precision the underlying model doesn't actually have, and the system's token set
has no "success"/"warning" hue to spend on a red/yellow/green scale anyway (only
destructive keeps real chroma). provenance is optional free text, rendered as
via {provenance} alongside the tier.
Composed by other AI-tier components
This isn't usually installed on its own — Smart Field and Selection Actions both
compose it directly for their proposal/classification results, and AI Approval Gate
(planned) will too. Install it standalone only if you're building a new AI-assisted
component that needs the same indicator.
Features
- Three tiers, never a percentage. A raw number would claim precision the underlying model doesn't have; the enum is the honest resolution.
- Decoration, not colour. The token set has no success/warning hue to spend on a red/yellow/green scale, so the tier is carried by filled bars plus a text label — which is also more accessible than a colour-only signal (DESIGN.md §3.2).
- The text label is the real signal; the bars are
aria-hiddenand supplementary, never the only way the level is communicated. - Optional provenance rendered inline as
via {source}, so a score can be shown next to its evidence rather than floating free. - Nothing to get wrong under reduced motion — it's presentational, with no animation and no keyboard interaction of its own.
Variants
The three tiers, side by side:
With provenance
Prefer this whenever you actually have a source. A score with evidence behind it is worth more than a score on its own — and if you can't show real evidence, say less, not more.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
confidence | "low" | "medium" | "high" | — | Required. |
provenance | string | — | Optional source caption, shown as via {provenance}. |
className | string | — |
Accessibility
- The tier's text label is the real signal — the bar indicator is
aria-hiddenand supplementary, never the only way the confidence level is communicated. - Purely presentational: no keyboard interaction of its own, no motion, nothing to get
wrong under
prefers-reduced-motion.
When not to use
A full sources/context/explanation surface is AI Context / Provenance Surface
(planned) — a richer, separate component. This one is a compact inline rating, not an
explanation panel.
why it's built this way
Engineering Notes
Extracted from two already-shipped components (Smart Field, Selection Actions) that had independently hand-rolled the identical tiered indicator — the concrete signal per the system's own 'a component is not an island' rule that this belongs as its own primitive rather than being re-derived a third time. Confidence is a three-tier enum, not a raw number, by deliberate and unchanged decision from Smart Field's original plan: a fabricated percentage would claim precision the model doesn't actually have, and the system's token set has no 'success'/'warning' hue to spend on a red/yellow/green scale anyway — only `destructive` keeps real chroma. A numeric-score-to-tier bucketing input was considered and deferred: no current consumer has a raw calibrated score to map, and adding that path now would solve a hypothetical need rather than an observed one. Provenance is folded into this component as an optional prop rather than left as a sibling element every consumer composes separately, since the two already-shipped call sites both rendered them side by side anyway — one import now covers both.
how it moves, and when it doesn't
Motion Notes
None, deliberately. This is a static presentational primitive with no state transitions of its own — any entrance/exit motion belongs to whatever container shows it (e.g. Smart Field's proposal panel), the same way Card's motion belongs to whatever wraps it, not to the primitive itself. Nothing here required a component-specific motion or reduced-motion branch, which is itself a signal the component is doing exactly what it needs to and no more.