# Hourglass (/docs/charts/hourglass)

Hourglass answers "how much time is gone _and_ how much remains?" — the two-sided story a progress bar can't tell. Sand
fills the top chamber (remaining) and the bottom (elapsed), and both areas are **area-true**: a naive linear-height fill
in a triangular bulb would overstate early progress by up to 2×, so the geometry solves for true proportional area. A
thin stream at the neck marks "running"; it disappears at both ends, because finished and not-started are shape-distinct
states.

```tsx
<span className="inline-flex gap-4 items-center">
  <Hourglass value={0.15} height={40} title="15% elapsed" />
  <Hourglass value={0.5} height={40} title="half" />
  <Hourglass value={0.85} height={40} title="85% elapsed" />
</span>
```

## Install

```tsx
import { Hourglass } from "@microcharts/react/hourglass";

<Hourglass value={0.75} title="Session" />
```

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 deadline or session-expiry read in a sentence, a TTL cell where remaining is the story, or a
  time-boxed tab or countdown.
- **Avoid for** — exact percentages (Progress), trends (Sparkline), or non-time fractions.


## Variants

```tsx
<Hourglass value={0.7} label="remaining" />
<Hourglass value={1} />
```

## Edge cases

```tsx
<Hourglass value={0} title="Not started" />
```

```tsx
<Hourglass value={1} title="Finished" />
```

```tsx
// unlike Thermometer, Hourglass has no calibrated domain to overflow past —
// value is a fraction, so 1.4 reads identically to 1 (finished)
<Hourglass value={1.4} title="Overrun" />
```

```tsx
<Hourglass value={Number.NaN} title="Invalid" />
```


## Why this default

`value` is the elapsed fraction — the same polarity as `Progress` — so the two compose in one product without
re-learning which way is which. The area-true solve is the load-bearing honesty rule: in an inherently nonlinear
container, the sand areas are exactly proportional to elapsed and remaining. The stream is a binary state mark, not
decoration, and is never animated in the static entry — it simply renders while `0 < value < 1`.

## Accessibility

The accessible name carries both sides — a glyph above reads **"70% elapsed, 30% remaining."** The interactive entry
cross-fades the sand levels on change (opacity plus a scale-from-the-floor settle, never a path interpolation) and
announces only when the value crosses a documented threshold (50 / 90 / 100%), so a streaming value never spams.

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` | Elapsed fraction 0–1 (like Progress). |
| `stream` | `boolean` | The running-sand cue (default true). |
| `label` | `"none" \| "remaining" \| "elapsed"` | Print the percent that matters to the context. |

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).
