# Thermometer (/docs/charts/thermometer)

Thermometer answers "where does this value sit on a calibrated range, and how close to the goal?" A column fills a
ticked tube; the ticks calibrate the read, which is what buys the precision. The fill always anchors at the bottom of
the range — never re-zeroed, never log — and an optional target line crosses the tube to mark the goal. The bulb is
instrument chrome (always full); it is not data, so its area means nothing.

```tsx
<Thermometer value={72} target={80} title="Fundraiser" height={56} />
```

## Install

```tsx
import { Thermometer } from "@microcharts/react/thermometer";

<Thermometer value={72} target={80} title="Fundraiser" />
```

Setup (package + stylesheet): [Quickstart](/docs/quickstart#set-up-with-an-ai-agent) or paste [`/agent-setup.md`](/agent-setup.md) into your agent.


## When to use it

- **Good for** — a fundraising or goal-progress read, a capacity or utilization gauge in a cell, or any value against a
  stated range.
- **Avoid for** — trends (Sparkline), proportions of a whole (SegmentedBar), or many series.


## Variants

```tsx
<Thermometer value={62} orientation="horizontal" bulb={false} />
<Thermometer value={72} domain={[32, 100]} ticks={[32, 50, 68, 86, 100]} />
```

## Edge cases

```tsx
<Thermometer value={130} domain={[0, 100]} title="Overrun" />
```

```tsx
<Thermometer value={0} title="Empty" />
```

```tsx
<Thermometer
  value={7234}
  domain={[0, 10000]}
  target={8000}
  format={{ maximumFractionDigits: 0 }}
  locale="de-DE"
/>
```

The accessible summary's value, domain, and target all go through the same locale-aware formatter, so "7,234" becomes
"7.234" in German grouping.


## Why this default

Vertical with the bulb is the default because the instrument metaphor is the point — a filling tube reads as "toward the
goal" instantly. Horizontal exists for table cells where a vertical tube cannot fit, and `bulb={false}` drops the
reservoir when the metaphor runs too warm for the context. The `domain` defaults to `[0, 100]` because a calibrated
instrument needs a stated range; auto-fitting would silently move the scale under the reader. A value beyond the domain
clamps the fill but the accessible name always reports the true number — the reading is never silently clipped.

## Accessibility

The accessible name states the value on its scale — **"62 on a 0–100 scale."** — and appends the goal when a target is
set. The interactive entry reveals the exact value on hover or focus, glides the fill to its new level with a
reduced-motion-gated transition, and announces each change through a polite live region.

This chart is a single unit, so there is nothing to rove between: a click, tap, `Enter` or `Space` selects it
and fires `onSelect`, and no selection stays pinned. That is the scalar half of the shared
[interaction contract](/docs/accessibility#one-interaction-contract).

## Props

| Prop | Type | Description |
| --- | --- | --- |
| `value` (required) | `number` | The reading. |
| `target` | `number` | A goal tick across the tube. |
| `domain` | `[number, number]` | The calibrated range (default [0, 100]). |
| `ticks` | `number \| number[]` | Tick count or explicit values. |
| `orientation` | `"vertical" \| "horizontal"` | Horizontal fits table cells. |
| `bulb` | `boolean` | Draw the reservoir bulb (default true). |
| `animate` | `boolean` | (interactive) Opt-in entrance motion when the chart mounts client-side — add `import "@microcharts/react/motion"` once. Inert on the server, on hydrated server HTML, and under `prefers-reduced-motion`. |

Plus the shared grammar — `data`, `domain`, `color`, `title`, `summary`, `format` — and the layout props (`width`, `height`, `className`, `style`) that every chart accepts. Interactive entries also share `animate` and `live`, and — wherever a chart has more than one navigable unit — `onActive`, `onSelect`, `selectedIndex` and `defaultSelectedIndex`; and — wherever the chart shows a hover value — `readout`. See [the shared grammar](/docs/quickstart#the-shared-grammar).
