# FoldedDayBand (/docs/charts/folded-day-band)

FoldedDayBand answers "what does a typical period look like — and is the current one typical?". It folds many days (or
weeks, or any cycle) onto a single period axis and shows the median with 25–75 and 5–95 percentile envelopes. Drop in a
`today` overlay and the chart answers the second question: is right now inside the usual band, or an outlier?

```tsx
import { FoldedDayBand } from "@microcharts/react/folded-day-band";

const curve = (h) => 40 + 42 _ Math.max(0, 1 - Math.abs(h - 14) / 10); const observations = Array.from({ length: 14 },
(\_d, d) => Array.from({ length: 24 }, (\_h, h) => ({ t: d _ 24 + h, value: Math.round(curve(h) + Math.sin(d + h) \* 8),
})), ).flat(); const today = Array.from({ length: 24 }, (\_h, h) => ({ t: h, value: Math.round(curve(h) + 14), }));

<FoldedDayBand data={observations} today={today} title="Typical day" />
```

## Install

```tsx
import { FoldedDayBand } from "@microcharts/react/folded-day-band";

<FoldedDayBand data={observations} today={today} title="Typical day" />
```

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** — typical-day traffic or load profiles, on-call or energy capacity planning.
- **Avoid for** — a raw time series (Sparkline) or a single period with nothing to fold.


## Variants

```tsx
<FoldedDayBand data={observations} percentiles={[[25, 75]]} />
<FoldedDayBand
  data={observations}
  format={{ minimumFractionDigits: 1, maximumFractionDigits: 1 }}
  locale="de-DE"
/>
```

`format` also takes `Intl.NumberFormatOptions` — with a `locale`, the accessible summary's fold position and peak value
follow that locale's own decimal mark ("14,0" in German, not "14.0"). The band and median line themselves don't change
shape; only the announced numbers are localized.

## Edge cases

```tsx
<FoldedDayBand data={[{ t: 3, value: 10 }]} title="Single observation" />
```

```tsx
// every bin lands on the same value — the band and median still render,
// as a flat line, not an empty chart
<FoldedDayBand
  data={Array.from({ length: 48 }, (_v, i) => ({ t: i, value: 7 }))}
/>
```

A single observation reports a real accessible name (median and peak both equal that one value) but has no width to fold
across, so nothing visibly paints — the chart is accessible-first even when there's too little data to draw. Identical
values across every bin still render as a flat line, distinct from an empty `data` array, which renders nothing and
announces "No data."


## Why this default

Two envelopes plus a median is the typical-day grammar that clinical glucose profiles standardized on. The envelopes
come from real per-bin quantiles — never smoothed across bins into a shape the data doesn't support — and the outer
boundary fades so 5–95 doesn't read as a hard limit. When a bin has too few observations the band collapses to the
median there rather than inventing a width.

## Accessibility

The accessible name reports the peak — **"Median peaks at 14 (82.5)."** The interactive entry roves the folded axis with
←/→, announcing the median and middle-half at each position.

The interactive entry follows the shared [interaction contract](/docs/accessibility#one-interaction-contract):
arrow keys rove between units on both axes, `Home` and `End` jump to the ends, and a click, tap, `Enter` or
`Space` selects a unit — pinning its readout so it survives blur, until you select it again or press `Escape`.
On touch, a tap pins and a drag scrubs.

## Props

| Prop | Type | Description |
| --- | --- | --- |
| `data` (required) | `{ t, value }[]` | Raw observations across many periods. |
| `period` | `number` | Fold length (168 folds a week). |
| `today` | `{ t, value }[]` | The current period overlaid. |
| `percentiles` | `[number, number][]` | Percentile pairs, outermost last. |
| `bins` | `number` | Fold-axis resolution (default 24). |
| `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).
