# Hourglass (/docs/charts/hourglass)

A session expires in nine minutes, and you need both halves of that: how much is gone and how much is left. Hourglass
shows both. Sand fills the top chamber for remaining and the bottom for elapsed, and both areas are **area-true**: a
linear-height fill in a triangular bulb would overstate early progress by up to 2×, so the geometry solves for true
proportional area instead. `value` is the elapsed fraction, the same polarity as `Progress`, so the two compose in one
product without re-learning which way is which. A thin stream at the neck renders while `0 < value < 1` and marks the
running state; it disappears at both ends, so finished and not-started are shape-distinct.

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

## Try it

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

<Hourglass
  value={0.75}
/>
```

## When to use it

Use it 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. For exact percentages use Progress, for trends use Sparkline, and for fractions that aren't time use a
chart that doesn't imply a clock.

## Sizing

**TTL cell — remaining is the story**

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

**finished is shape-distinct (no stream)**

```tsx
<Hourglass value={1} />
```

## 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" />
```

Out-of-range values clamp to 0–1 in the drawing and in the accessible name, and `NaN` renders as 0 elapsed. Both ends
drop the neck stream, so a not-started or finished glyph never reads as a running timer. In the static entry the stream
is a state mark and is never animated.

## Four homes

**In a sentence**

```tsx
<p>
  Session time remaining{" "}
  <span className="mc-inline">
    <Hourglass value={0.7} summary={false} />
  </span>{" "}
  — 75% elapsed, renew soon.
</p>
```

**In a table cell**

```tsx
<td>
  <Hourglass value={0.7} />
</td>
```

**In a KPI card**

```tsx
<div className="kpi">
  <span className="figure">75%</span>
  <span className="unit">elapsed</span>
  <Hourglass value={0.7} />
</div>
```

**In a tab header**

```tsx
<button className="tab">
  Admin <Hourglass value={0.7} />
</button>
```

## 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, with opacity plus a scale-from-the-floor settle rather than a path interpolation.
It announces only when the value crosses 50, 90, or 100%, so a streaming value never floods a screen reader.

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).
Hover or focus also reveals the reading itself in a floating chip, for the sizes and label modes where the mark
does not print it; `readout={false}` drops the chip and keeps everything else.

## 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. |
| `fontSize` | `number` | Type size of the percent numeral, in viewBox units (default 8). |

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