# Lilt Charts
> React chart cards for dashboards. Pass your rows and name the fields. Each family supplies its own headline, readout, and interaction. Package: `@lilt-ui/charts` 0.13.1 (MIT). Requires React and React DOM 19.
## Install
```bash
npm install @lilt-ui/charts
```
pnpm, yarn, and bun work the same way: `pnpm add @lilt-ui/charts`, `yarn add @lilt-ui/charts`, `bun add @lilt-ui/charts`.
Import the stylesheet once, in the root layout or app entry:
```ts
import '@lilt-ui/charts/styles.css';
```
## Rules
- Every card is a client component. In the Next.js App Router, render cards from a file that starts with `'use client'`.
- Import cards and parts from `@lilt-ui/charts`, and finance cards (candlestick, indicators, price, depth, order book, portfolio) from `@lilt-ui/charts/finance`. Server-safe data helpers (`summarizeRange`, `toChartCsv`, `summarizeFunnelStages`) are also in `@lilt-ui/charts/data`.
- Card titles are optional: omit `title` to render no title. `header={false}` removes the entire header, including headline, delta and period controls. Supply an `aria-label` when your app owns the visible heading. Pass the selected rows through `data` when your app owns period selection.
- Where a card supports legend layouts, `legend={false}` removes the legend without changing its data. `surface="ghost"` only removes the visual frame; it does not hide content. Radial charts keep their centre, pointer inspection, and keyboard inspection when the legend is hidden; Escape clears a pin in every layout.
- Pass rows as they are. `x`, `category`, `value`, and each series `key` name fields of the row type; TypeScript rejects unknown or non-numeric fields.
- `null` is a missing value and draws as a gap; `0` is a measurement. Never replace missing values with zero.
- Format numbers with `valueFormat`, which takes `Intl.NumberFormatOptions`, e.g. `{ style: 'currency', currency: 'USD' }`.
- For rates and levels such as latency or active users, set `aggregate` (`'mean'`, `'last'`, or `'max'`) so the headline is not a meaningless total.
- Give Area, Line, Bar, Combo, and Stat cards the same `sync` name to link their hover; Stat requires `x`. A click pins every linked card (Alt-click or Alt+Enter pins one card only). Area, Line, Bar, and Combo support `target` goal lines and supplied `forecast` rows. Stat uses `target` for its meter or ring and has no `forecast` prop.
- Cards follow shadcn theme variables (`--card`, `--card-foreground`, `--muted-foreground`, `--border`, `--ring`, `--chart-1` to `--chart-5`). Lilt styles sit in the `lilt` cascade layer, so app CSS overrides them.
## Area chart: `AreaChartCard`
Trends over time, layered or stacked. Docs: https://liltui.vercel.app/charts/area
```tsx
import { AreaChartCard } from '@lilt-ui/charts';
```
### Complete examples
#### Area chart card
```tsx
'use client';
import { AreaChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "year", "label": "This year", "data": [
{ "month": "Jan", "organic": 2400, "referral": 1200, "paid": 800 },
{ "month": "Feb", "organic": 2800, "referral": 1400, "paid": 700 },
{ "month": "Mar", "organic": 3100, "referral": 1500, "paid": 900 },
{ "month": "Apr", "organic": 2900, "referral": 1700, "paid": 1100 },
{ "month": "May", "organic": 3600, "referral": 1900, "paid": 1000 },
{ "month": "Jun", "organic": 4100, "referral": 2100, "paid": 1300 },
{ "month": "Jul", "organic": 4500, "referral": 2400, "paid": 1400 },
{ "month": "Aug", "organic": 4300, "referral": 2500, "paid": 1600 },
{ "month": "Sep", "organic": 4900, "referral": 2600, "paid": 1500 },
{ "month": "Oct", "organic": 5400, "referral": 2900, "paid": 1800 },
{ "month": "Nov", "organic": 5800, "referral": 3100, "paid": 2000 },
{ "month": "Dec", "organic": 6700, "referral": 3500, "paid": 2200 },
], "delta": 0.184 },
{ "id": "last-year", "label": "Last year", "data": [
{ "month": "Jan", "organic": 2100, "referral": 1100, "paid": 900 },
{ "month": "Feb", "organic": 2300, "referral": 1200, "paid": 900 },
{ "month": "Mar", "organic": 2500, "referral": 1300, "paid": 1000 },
{ "month": "Apr", "organic": 2600, "referral": 1400, "paid": 1000 },
{ "month": "May", "organic": 2900, "referral": 1500, "paid": 1100 },
{ "month": "Jun", "organic": 3300, "referral": 1700, "paid": 1200 },
{ "month": "Jul", "organic": 3500, "referral": 1800, "paid": 1200 },
{ "month": "Aug", "organic": 3600, "referral": 2000, "paid": 1300 },
{ "month": "Sep", "organic": 3900, "referral": 2100, "paid": 1400 },
{ "month": "Oct", "organic": 4200, "referral": 2300, "paid": 1500 },
{ "month": "Nov", "organic": 4600, "referral": 2500, "paid": 1600 },
{ "month": "Dec", "organic": 5100, "referral": 2700, "paid": 1800 },
], "delta": 0.062 },
];
export function Example() {
return (
);
}
```
#### Forecast fan
Two supplied forecast envelopes show widening uncertainty. Hovering exposes every interval bound. The headline summarizes observed readings, and the chart never estimates a forecast.
```tsx
'use client';
import { AreaChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This year", "data": [
{ "month": "M1", "revenue": 120, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M2", "revenue": 134, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M3", "revenue": 144, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M4", "revenue": 149, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M5", "revenue": 152, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M6", "revenue": 154, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M7", "revenue": 160, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M8", "revenue": 171, "low95": 164, "high95": 178, "low80": 166.8, "high80": 175.2 },
{ "month": "M9", "revenue": 185, "low95": 171, "high95": 199, "low80": 176.6, "high80": 193.4 },
{ "month": "M10", "revenue": 198, "low95": 177, "high95": 219, "low80": 185.4, "high80": 210.6 },
{ "month": "M11", "revenue": 208, "low95": 180, "high95": 236, "low80": 191.2, "high80": 224.8 },
{ "month": "M12", "revenue": 213, "low95": 178, "high95": 248, "low80": 192, "high80": 234 },
] },
{ "id": "previous", "label": "Last year", "data": [
{ "month": "M1", "revenue": 101, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M2", "revenue": 124, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M3", "revenue": 128, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M4", "revenue": 116, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M5", "revenue": 116, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M6", "revenue": 132, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M7", "revenue": 149, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M8", "revenue": 149, "low95": 142, "high95": 155, "low80": 144.9, "high80": 152.2 },
{ "month": "M9", "revenue": 142, "low95": 131, "high95": 152, "low80": 135.2, "high80": 148 },
{ "month": "M10", "revenue": 153, "low95": 137, "high95": 169, "low80": 143, "high80": 162.5 },
{ "month": "M11", "revenue": 183, "low95": 158, "high95": 207, "low80": 167.8, "high80": 197.3 },
{ "month": "M12", "revenue": 198, "low95": 165, "high95": 230, "low80": 178, "high80": 217 },
] },
];
export function Example() {
return (
);
}
```
#### Channel mix
A centered stream shows changing channel composition. Thickness carries the measurement; dots inspect supplied readings. Missing contributions break the whole period.
```tsx
'use client';
import { StreamgraphCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const channelMix = [
{ "week": "W1", "organic": 80, "referral": 67, "paid": 25, "direct": 47 },
{ "week": "W2", "organic": 96, "referral": 63, "paid": 43, "direct": 46 },
{ "week": "W3", "organic": 109, "referral": 53, "paid": 53, "direct": 43 },
{ "week": "W4", "organic": 118, "referral": 40, "paid": 52, "direct": 39 },
{ "week": "W5", "organic": 121, "referral": 29, "paid": 44, "direct": 35 },
{ "week": "W6", "organic": 118, "referral": 23, "paid": 36, "direct": 30 },
{ "week": "W7", "organic": 111, "referral": 25, "paid": 37, "direct": 26 },
{ "week": "W8", "organic": 101, "referral": 34, "paid": 49, "direct": 24 },
{ "week": "W9", "organic": 91, "referral": 47, "paid": 67, "direct": 23 },
{ "week": "W10", "organic": 83, "referral": 59, "paid": 84, "direct": 24 },
{ "week": "W11", "organic": 81, "referral": 66, "paid": 93, "direct": 27 },
{ "week": "W12", "organic": 84, "referral": 66, "paid": 91, "direct": 31 },
{ "week": "W13", "organic": 93, "referral": 58, "paid": 82, "direct": 36 },
];
export function Example() {
return (
);
}
```
#### Dates and a previous period
Date values on x are detected automatically. A dashed series draws a reference line without a fill.
```tsx
'use client';
import { AreaChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "Sep 1–21", "data": [
{ "date": new Date('2026-09-01T00:00:00.000Z'), "revenue": 2180, "previous": 1950 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "revenue": 2340, "previous": 2050 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "revenue": 2110, "previous": 2020 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "revenue": 2670, "previous": 2140 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "revenue": 2510, "previous": 2220 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "revenue": 2880, "previous": 2300 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "revenue": 2750, "previous": 2250 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "revenue": 3090, "previous": 2470 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "revenue": 2870, "previous": 2390 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "revenue": 3360, "previous": 2680 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "revenue": 3190, "previous": 2760 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "revenue": 3520, "previous": 2840 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "revenue": 3440, "previous": 2920 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "revenue": 3710, "previous": 3060 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "revenue": 3580, "previous": 3010 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "revenue": 3960, "previous": 3180 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "revenue": 3820, "previous": 3120 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "revenue": 4150, "previous": 3300 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "revenue": 4030, "previous": 3260 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "revenue": 4420, "previous": 3410 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "revenue": 4310, "previous": 3380 },
], "delta": 0.156 },
{ "id": "previous", "label": "Aug 11–31", "data": [
{ "date": new Date('2026-08-11T00:00:00.000Z'), "revenue": 1831, "previous": 1638 },
{ "date": new Date('2026-08-12T00:00:00.000Z'), "revenue": 2169, "previous": 1900 },
{ "date": new Date('2026-08-13T00:00:00.000Z'), "revenue": 1870, "previous": 1791 },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "revenue": 2078, "previous": 1665 },
{ "date": new Date('2026-08-15T00:00:00.000Z'), "revenue": 1909, "previous": 1688 },
{ "date": new Date('2026-08-16T00:00:00.000Z'), "revenue": 2475, "previous": 1977 },
{ "date": new Date('2026-08-17T00:00:00.000Z'), "revenue": 2557, "previous": 2092 },
{ "date": new Date('2026-08-18T00:00:00.000Z'), "revenue": 2684, "previous": 2146 },
{ "date": new Date('2026-08-19T00:00:00.000Z'), "revenue": 2197, "previous": 1830 },
{ "date": new Date('2026-08-20T00:00:00.000Z'), "revenue": 2592, "previous": 2067 },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "revenue": 2800, "previous": 2423 },
{ "date": new Date('2026-08-22T00:00:00.000Z'), "revenue": 3269, "previous": 2638 },
{ "date": new Date('2026-08-23T00:00:00.000Z'), "revenue": 2923, "previous": 2481 },
{ "date": new Date('2026-08-24T00:00:00.000Z'), "revenue": 2806, "previous": 2315 },
{ "date": new Date('2026-08-25T00:00:00.000Z'), "revenue": 2812, "previous": 2365 },
{ "date": new Date('2026-08-26T00:00:00.000Z'), "revenue": 3542, "previous": 2845 },
{ "date": new Date('2026-08-27T00:00:00.000Z'), "revenue": 3528, "previous": 2882 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "revenue": 3445, "previous": 2740 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "revenue": 3027, "previous": 2449 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "revenue": 3546, "previous": 2736 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "revenue": 3916, "previous": 3071 },
], "delta": 0.07 },
];
export function Example() {
return (
);
}
```
#### Target
`target` draws a labeled goal line. At rest the header counts days on target; hover reads each day against it.
```tsx
'use client';
import { AreaChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This year", "data": [
{ "date": new Date('2026-09-01T00:00:00.000Z'), "revenue": 2180, "previous": 1950 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "revenue": 2340, "previous": 2050 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "revenue": 2110, "previous": 2020 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "revenue": 2670, "previous": 2140 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "revenue": 2510, "previous": 2220 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "revenue": 2880, "previous": 2300 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "revenue": 2750, "previous": 2250 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "revenue": 3090, "previous": 2470 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "revenue": 2870, "previous": 2390 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "revenue": 3360, "previous": 2680 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "revenue": 3190, "previous": 2760 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "revenue": 3520, "previous": 2840 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "revenue": 3440, "previous": 2920 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "revenue": 3710, "previous": 3060 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "revenue": 3580, "previous": 3010 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "revenue": 3960, "previous": 3180 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "revenue": 3820, "previous": 3120 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "revenue": 4150, "previous": 3300 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "revenue": 4030, "previous": 3260 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "revenue": 4420, "previous": 3410 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "revenue": 4310, "previous": 3380 },
] },
{ "id": "previous", "label": "Last year", "data": [
{ "date": new Date('2025-09-01T00:00:00.000Z'), "revenue": 1831, "previous": 1638 },
{ "date": new Date('2025-09-02T00:00:00.000Z'), "revenue": 2169, "previous": 1900 },
{ "date": new Date('2025-09-03T00:00:00.000Z'), "revenue": 1870, "previous": 1791 },
{ "date": new Date('2025-09-04T00:00:00.000Z'), "revenue": 2078, "previous": 1665 },
{ "date": new Date('2025-09-05T00:00:00.000Z'), "revenue": 1909, "previous": 1688 },
{ "date": new Date('2025-09-06T00:00:00.000Z'), "revenue": 2475, "previous": 1977 },
{ "date": new Date('2025-09-07T00:00:00.000Z'), "revenue": 2557, "previous": 2092 },
{ "date": new Date('2025-09-08T00:00:00.000Z'), "revenue": 2684, "previous": 2146 },
{ "date": new Date('2025-09-09T00:00:00.000Z'), "revenue": 2197, "previous": 1830 },
{ "date": new Date('2025-09-10T00:00:00.000Z'), "revenue": 2592, "previous": 2067 },
{ "date": new Date('2025-09-11T00:00:00.000Z'), "revenue": 2800, "previous": 2423 },
{ "date": new Date('2025-09-12T00:00:00.000Z'), "revenue": 3269, "previous": 2638 },
{ "date": new Date('2025-09-13T00:00:00.000Z'), "revenue": 2923, "previous": 2481 },
{ "date": new Date('2025-09-14T00:00:00.000Z'), "revenue": 2806, "previous": 2315 },
{ "date": new Date('2025-09-15T00:00:00.000Z'), "revenue": 2812, "previous": 2365 },
{ "date": new Date('2025-09-16T00:00:00.000Z'), "revenue": 3542, "previous": 2845 },
{ "date": new Date('2025-09-17T00:00:00.000Z'), "revenue": 3528, "previous": 2882 },
{ "date": new Date('2025-09-18T00:00:00.000Z'), "revenue": 3445, "previous": 2740 },
{ "date": new Date('2025-09-19T00:00:00.000Z'), "revenue": 3027, "previous": 2449 },
{ "date": new Date('2025-09-20T00:00:00.000Z'), "revenue": 3546, "previous": 2736 },
{ "date": new Date('2025-09-21T00:00:00.000Z'), "revenue": 3916, "previous": 3071 },
] },
];
export function Example() {
return (
);
}
```
#### Forecast
Rows from `forecast.from` onward are projections: dotted, shaded, and left out of the headline and tiles. `lower` and `upper` add the range around them.
```tsx
'use client';
import { AreaChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This year", "data": [
{ "date": new Date('2026-09-01T00:00:00.000Z'), "revenue": 2180, "low": null, "high": null },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "revenue": 2340, "low": null, "high": null },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "revenue": 2110, "low": null, "high": null },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "revenue": 2670, "low": null, "high": null },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "revenue": 2510, "low": null, "high": null },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "revenue": 2880, "low": null, "high": null },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "revenue": 2750, "low": null, "high": null },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "revenue": 3090, "low": null, "high": null },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "revenue": 2870, "low": null, "high": null },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "revenue": 3360, "low": null, "high": null },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "revenue": 3190, "low": null, "high": null },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "revenue": 3520, "low": null, "high": null },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "revenue": 3440, "low": null, "high": null },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "revenue": 3710, "low": null, "high": null },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "revenue": 3580, "low": null, "high": null },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "revenue": 3960, "low": null, "high": null },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "revenue": 3820, "low": null, "high": null },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "revenue": 4150, "low": null, "high": null },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "revenue": 4030, "low": null, "high": null },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "revenue": 4420, "low": null, "high": null },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "revenue": 4310, "low": 4310, "high": 4310 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "revenue": 4480, "low": 4323, "high": 4614 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "revenue": 4560, "low": 4241, "high": 4834 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "revenue": 4610, "low": 4126, "high": 5025 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "revenue": 4700, "low": 4042, "high": 5264 },
{ "date": new Date('2026-09-26T00:00:00.000Z'), "revenue": 4760, "low": 3927, "high": 5474 },
{ "date": new Date('2026-09-27T00:00:00.000Z'), "revenue": 4850, "low": 3832, "high": 5723 },
{ "date": new Date('2026-09-28T00:00:00.000Z'), "revenue": 4920, "low": 3715, "high": 5953 },
] },
{ "id": "previous", "label": "Last year", "data": [
{ "date": new Date('2025-09-01T00:00:00.000Z'), "revenue": 1831, "low": null, "high": null },
{ "date": new Date('2025-09-02T00:00:00.000Z'), "revenue": 2169, "low": null, "high": null },
{ "date": new Date('2025-09-03T00:00:00.000Z'), "revenue": 1870, "low": null, "high": null },
{ "date": new Date('2025-09-04T00:00:00.000Z'), "revenue": 2078, "low": null, "high": null },
{ "date": new Date('2025-09-05T00:00:00.000Z'), "revenue": 1909, "low": null, "high": null },
{ "date": new Date('2025-09-06T00:00:00.000Z'), "revenue": 2475, "low": null, "high": null },
{ "date": new Date('2025-09-07T00:00:00.000Z'), "revenue": 2557, "low": null, "high": null },
{ "date": new Date('2025-09-08T00:00:00.000Z'), "revenue": 2684, "low": null, "high": null },
{ "date": new Date('2025-09-09T00:00:00.000Z'), "revenue": 2197, "low": null, "high": null },
{ "date": new Date('2025-09-10T00:00:00.000Z'), "revenue": 2592, "low": null, "high": null },
{ "date": new Date('2025-09-11T00:00:00.000Z'), "revenue": 2800, "low": null, "high": null },
{ "date": new Date('2025-09-12T00:00:00.000Z'), "revenue": 3269, "low": null, "high": null },
{ "date": new Date('2025-09-13T00:00:00.000Z'), "revenue": 2923, "low": null, "high": null },
{ "date": new Date('2025-09-14T00:00:00.000Z'), "revenue": 2806, "low": null, "high": null },
{ "date": new Date('2025-09-15T00:00:00.000Z'), "revenue": 2812, "low": null, "high": null },
{ "date": new Date('2025-09-16T00:00:00.000Z'), "revenue": 3542, "low": null, "high": null },
{ "date": new Date('2025-09-17T00:00:00.000Z'), "revenue": 3528, "low": null, "high": null },
{ "date": new Date('2025-09-18T00:00:00.000Z'), "revenue": 3445, "low": null, "high": null },
{ "date": new Date('2025-09-19T00:00:00.000Z'), "revenue": 3027, "low": null, "high": null },
{ "date": new Date('2025-09-20T00:00:00.000Z'), "revenue": 3546, "low": null, "high": null },
{ "date": new Date('2025-09-21T00:00:00.000Z'), "revenue": 3916, "low": 3916, "high": 3916 },
{ "date": new Date('2025-09-22T00:00:00.000Z'), "revenue": 4097, "low": 3953, "high": 4219 },
{ "date": new Date('2025-09-23T00:00:00.000Z'), "revenue": 3699, "low": 3440, "high": 3921 },
{ "date": new Date('2025-09-24T00:00:00.000Z'), "revenue": 3458, "low": 3095, "high": 3769 },
{ "date": new Date('2025-09-25T00:00:00.000Z'), "revenue": 3857, "low": 3317, "high": 4320 },
{ "date": new Date('2025-09-26T00:00:00.000Z'), "revenue": 4377, "low": 3611, "high": 5034 },
{ "date": new Date('2025-09-27T00:00:00.000Z'), "revenue": 4374, "low": 3456, "high": 5161 },
{ "date": new Date('2025-09-28T00:00:00.000Z'), "revenue": 3904, "low": 2948, "high": 4724 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per x position, one numeric field per series.
const visitors = [
{ month: 'Jan', organic: 2400, referral: 400, paid: 800, target: 3000 },
{ month: 'Feb', organic: 2800, referral: 500, paid: 700, target: 3200 },
];
```
Pass your rows as they are. `x` and each series `key` name fields on the row, and TypeScript rejects keys that don’t exist or aren’t numbers. Totals, tiles, and hover values are derived. `null` is a gap, not zero. With `stack="percent"`, each complete period fills to 100% and the headline and tiles read shares of the latest period; a missing, negative, or zero-total period becomes a gap across the whole stack.
### Period select
```tsx
```
### Hover
Hovering the plot moves Lilt’s hover dots along each series, with soft pills on the axes that fade the labels they pass over. The y pill follows the line nearest the pointer, even while a point is pinned. The headline counts to the hovered total and every tile shows its value at that point. Set `hover` to `tooltip` or `headline` for a different readout.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `data` (`Row[]`): One row per x position. Omit when using ranges.
- `x` (`key of Row`): Text, number, or Date field for the x axis.
- `series` (`{ key, label?, color?, dashed? }[]`): Numeric fields to plot, checked against your row type. Dashed series are references left out of the headline.
- `stack` (`boolean | 'percent'`): Stack the areas: `true` adds them, `percent` shows shares. Omit to overlap them. Dashed series stay lines over the stack.
- `curve` (`'smooth' | 'linear'`): Monotone spline or straight segments.
- `bleed` (`boolean`): Run areas to the card edges with a soft fade. Defaults to true.
- `pillValue` (`'series' | 'stack'`): In stacks, show a series’ own value (default) or its stacked height.
- `depth` (`boolean`): Draws each line as a lit tube with a soft shadow over its fade. Every point reads where the flat line puts it.
- `decimate` (`boolean`): Draw a long series from each pixel column’s first, last, lowest and highest point, so tens of thousands of points stay fast. Hover, tiles and exports still read every row. Defaults to true.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `delta` (`number`): Fractional change for the chip: 0.082 shows +8.2%.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `headline` (`number`): Resting headline. Defaults to the aggregate of non-reference series; dashed series are excluded.
- `range` (`string`): Static period label in the header.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the data.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `tiles` (`boolean`): Per-series value tiles. Defaults to true; false hides the legend.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): False removes the legend without changing the data. How the legend under the plot lays out: value tiles (default), a compact inline key, list rows, tinted pills, or bars that also draw each value against the largest.
- `legendSwatch` (`'square' | 'dot' | 'line'`): The mark beside each legend label. Defaults to a rounded square.
- `height` (`number`): Plot height in pixels. Defaults to 240.
- `axis` (`'minimal' | 'dots' | 'inline' | 'ruler' | 'classic' | 'segmented' | { x, y }`): Axis preset. Minimal (default) labels only the x ends and has no grid. Set one per axis with `{ x, y }`; a segmented axis can take a `gradient` to read as a range.
- `hover` (`'pills' | 'tooltip' | 'strip' | 'headline'`): The one readout for the hovered point: pills on the axes (default), a tooltip with every series, a strip docked above the plot, or the headline and tiles alone.
- `hoverStyle` (`'soft' | 'solid' | 'accent'`): How the pills or tooltip look. Soft (default) is surface glass; accent tints it with the hovered series.
- `pillSeries` (`'nearest' | 'total' | key`): Which series the y pill reads and the tooltip leads with. Nearest (default) follows the pointer.
- `pillPosition` (`'auto' | 'mark' | 'axis'`): Where the value pill sits: above the hovered mark, or on the y axis. Auto picks mark when there are no y labels.
- `tooltipIndicator` (`'square' | 'dot' | 'line'`): Series marker on each tooltip row, with hover="tooltip". Square by default.
- `background` (`'dots' | 'grid' | 'lines' | 'none'`): Texture behind the marks. Dots by default, with a hover spotlight.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `axisInset` (`number`): Padding between the plot edges and axis labels or pills.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `compare` (`boolean | 'headline' | 'badge'`): Drag across the plot to compare two points in time. True or headline reads the change in the headline; badge reads it in the card’s tab and leaves the headline at rest.
- `target` (`number | { value, label? }`): A goal each point should reach: a labeled line, a “vs target” chip on hover, and a count of points on target at rest.
- `forecast` (`{ from, lower?, upper?, label?, bands?: { lower, upper, label }[] }`): Rows from `from` onward are projections: dotted and excluded from the headline. Supply lower/upper for one envelope, or bands ordered widest to narrowest for a fan on Line and unstacked Area. Every bound is inspectable; no forecast is estimated.
- `sync` (`string`): Link hover and pins with every card that uses the same name, matched by x value. A click pins them all, with a ghost pin on the others; Alt-click pins one card only.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `aggregate` (`'sum' | 'mean' | 'last' | 'max'`): Summary at rest: sum for counts, mean for rates, last for levels, or max for peaks. Area defaults to sum; Range defaults to mean.
- `headlineSeries` (`key of Row`): Numeric series whose value drives the headline instead of the combined total.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `formatAxisValue` (`(value: number) => string`): Custom compact axis value text.
- `formatX` (`(value: string | number | Date) => string`): Custom x label text.
- `xType` (`'category' | 'number' | 'time'`): Override inferred x type. Use time for numeric Unix timestamps in milliseconds.
- `spotlight` (`boolean`): Highlight the inspected position in the plot background. Defaults to true.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
### Streamgraph: StreamgraphCard
A centered stream shows changing channel composition. Thickness carries the measurement; dots inspect supplied readings. Missing contributions break the whole period. All three loading styles share the skeleton exit, entrance, pointer/keyboard pinning, touch glide, reduced motion, and accessible readings table. Aggregate marks report null as their original datum.
```tsx
import { StreamgraphCard } from '@lilt-ui/charts';
```
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 260. Dense lanes expand to keep every mark visible.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Legend layout; false hides it. Correlation defaults to false.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Legend marker, square by default.
- `x` (`x key of Row`): Unique ordered period. Strings follow input order; numeric/date positions preserve spacing.
- `series` (`CardSeries[]`): Nonnegative layers.
- `curve` (`'smooth' | 'linear'`): Basis interpolation (default) or straight boundaries.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Line chart: `LineChartCard`
Follow trends and compare changes over time. Docs: https://liltui.vercel.app/charts/line
```tsx
import { LineChartCard } from '@lilt-ui/charts';
```
### Complete examples
#### Line chart card
```tsx
'use client';
import { LineChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "three-weeks", "label": "Last 21 days", "data": [
{ "date": new Date('2026-09-01T00:00:00.000Z'), "desktop": 1840, "mobile": 1210, "goal": 4200 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "desktop": 1910, "mobile": 1290, "goal": 4200 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "desktop": 1780, "mobile": 1340, "goal": 4200 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "desktop": 2050, "mobile": 1420, "goal": 4200 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "desktop": 2210, "mobile": 1390, "goal": 4200 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "desktop": 1690, "mobile": 1580, "goal": 4200 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "desktop": 1620, "mobile": 1660, "goal": 4200 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "desktop": 2140, "mobile": 1610, "goal": 4200 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "desktop": 2260, "mobile": 1700, "goal": 4200 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "desktop": 2330, "mobile": 1760, "goal": 4200 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "desktop": 2190, "mobile": 1850, "goal": 4200 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "desktop": 2410, "mobile": 1930, "goal": 4200 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "desktop": 1880, "mobile": 2040, "goal": 4200 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "desktop": 1790, "mobile": 2120, "goal": 4200 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "desktop": 2380, "mobile": 2080, "goal": 4200 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "desktop": 2510, "mobile": 2190, "goal": 4200 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "desktop": 2470, "mobile": 2260, "goal": 4200 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "desktop": 2620, "mobile": 2310, "goal": 4200 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "desktop": 2560, "mobile": 2420, "goal": 4200 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "desktop": 2040, "mobile": 2530, "goal": 4200 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "desktop": 1960, "mobile": 2610, "goal": 4200 },
], "delta": 0.126 },
{ "id": "two-weeks", "label": "Last 14 days", "data": [
{ "date": new Date('2026-09-08T00:00:00.000Z'), "desktop": 2140, "mobile": 1610, "goal": 4200 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "desktop": 2260, "mobile": 1700, "goal": 4200 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "desktop": 2330, "mobile": 1760, "goal": 4200 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "desktop": 2190, "mobile": 1850, "goal": 4200 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "desktop": 2410, "mobile": 1930, "goal": 4200 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "desktop": 1880, "mobile": 2040, "goal": 4200 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "desktop": 1790, "mobile": 2120, "goal": 4200 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "desktop": 2380, "mobile": 2080, "goal": 4200 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "desktop": 2510, "mobile": 2190, "goal": 4200 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "desktop": 2470, "mobile": 2260, "goal": 4200 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "desktop": 2620, "mobile": 2310, "goal": 4200 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "desktop": 2560, "mobile": 2420, "goal": 4200 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "desktop": 2040, "mobile": 2530, "goal": 4200 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "desktop": 1960, "mobile": 2610, "goal": 4200 },
], "delta": 0.081 },
{ "id": "week", "label": "Last 7 days", "data": [
{ "date": new Date('2026-09-15T00:00:00.000Z'), "desktop": 2380, "mobile": 2080, "goal": 4200 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "desktop": 2510, "mobile": 2190, "goal": 4200 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "desktop": 2470, "mobile": 2260, "goal": 4200 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "desktop": 2620, "mobile": 2310, "goal": 4200 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "desktop": 2560, "mobile": 2420, "goal": 4200 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "desktop": 2040, "mobile": 2530, "goal": 4200 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "desktop": 1960, "mobile": 2610, "goal": 4200 },
], "delta": 0.034 },
];
export function Example() {
return (
);
}
```
#### Indexed growth
Series with different units start at 100 at their first finite observation. A zero baseline cannot be indexed and stays missing. The headline follows the latest value of the first series.
```tsx
'use client';
import { LineChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This period", "data": [
{ "month": "M1", "subscribers": 1200, "revenue": 28000 },
{ "month": "M2", "subscribers": 1308, "revenue": 31191 },
{ "month": "M3", "subscribers": 1389, "revenue": 34218 },
{ "month": "M4", "subscribers": 1439, "revenue": 36956 },
{ "month": "M5", "subscribers": 1485, "revenue": 39353 },
{ "month": "M6", "subscribers": 1555, "revenue": 41438 },
{ "month": "M7", "subscribers": 1658, "revenue": 43318 },
{ "month": "M8", "subscribers": 1770, "revenue": 45149 },
{ "month": "M9", "subscribers": 1860, "revenue": 47100 },
{ "month": "M10", "subscribers": 1917, "revenue": 49311 },
] },
{ "id": "previous", "label": "Last period", "data": [
{ "month": "M1", "subscribers": 1008, "revenue": 23520 },
{ "month": "M2", "subscribers": 1212, "revenue": 28905 },
{ "month": "M3", "subscribers": 1231, "revenue": 30331 },
{ "month": "M4", "subscribers": 1120, "revenue": 28756 },
{ "month": "M5", "subscribers": 1129, "revenue": 29928 },
{ "month": "M6", "subscribers": 1336, "revenue": 35610 },
{ "month": "M7", "subscribers": 1542, "revenue": 40280 },
{ "month": "M8", "subscribers": 1538, "revenue": 39222 },
{ "month": "M9", "subscribers": 1424, "revenue": 36055 },
{ "month": "M10", "subscribers": 1479, "revenue": 38040 },
] },
];
export function Example() {
return (
);
}
```
#### Forecast fan
Two supplied forecast envelopes show widening uncertainty. Hovering exposes every interval bound. The headline summarizes observed readings, and the chart never estimates a forecast.
```tsx
'use client';
import { LineChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This period", "data": [
{ "month": "M1", "revenue": 120, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M2", "revenue": 134, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M3", "revenue": 144, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M4", "revenue": 149, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M5", "revenue": 152, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M6", "revenue": 154, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M7", "revenue": 160, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M8", "revenue": 171, "low95": 164, "high95": 178, "low80": 166.8, "high80": 175.2 },
{ "month": "M9", "revenue": 185, "low95": 171, "high95": 199, "low80": 176.6, "high80": 193.4 },
{ "month": "M10", "revenue": 198, "low95": 177, "high95": 219, "low80": 185.4, "high80": 210.6 },
{ "month": "M11", "revenue": 208, "low95": 180, "high95": 236, "low80": 191.2, "high80": 224.8 },
{ "month": "M12", "revenue": 213, "low95": 178, "high95": 248, "low80": 192, "high80": 234 },
] },
{ "id": "previous", "label": "Last period", "data": [
{ "month": "M1", "revenue": 101, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M2", "revenue": 124, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M3", "revenue": 128, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M4", "revenue": 116, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M5", "revenue": 116, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M6", "revenue": 132, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M7", "revenue": 149, "low95": null, "high95": null, "low80": null, "high80": null },
{ "month": "M8", "revenue": 149, "low95": 142, "high95": 155, "low80": 144.9, "high80": 152.2 },
{ "month": "M9", "revenue": 142, "low95": 131, "high95": 152, "low80": 135.2, "high80": 148 },
{ "month": "M10", "revenue": 153, "low95": 137, "high95": 169, "low80": 143, "high80": 162.5 },
{ "month": "M11", "revenue": 183, "low95": 158, "high95": 207, "low80": 167.8, "high80": 197.3 },
{ "month": "M12", "revenue": 198, "low95": 165, "high95": 230, "low80": 178, "high80": 217 },
] },
];
export function Example() {
return (
);
}
```
#### Values that hold until they change
For levels that change at a moment and hold, like seats, plans, or prices. Last shows the current level.
```tsx
'use client';
import { LineChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This period", "data": [
{ "week": "W1", "pro": 120, "team": 40 },
{ "week": "W2", "pro": 120, "team": 40 },
{ "week": "W3", "pro": 135, "team": 40 },
{ "week": "W4", "pro": 135, "team": 64 },
{ "week": "W5", "pro": 150, "team": 64 },
{ "week": "W6", "pro": 150, "team": 64 },
{ "week": "W7", "pro": 142, "team": 88 },
{ "week": "W8", "pro": 165, "team": 88 },
{ "week": "W9", "pro": 165, "team": 112 },
{ "week": "W10", "pro": 180, "team": 112 },
], "delta": 0.5 },
{ "id": "previous", "label": "Last period", "data": [
{ "week": "W1", "pro": 101, "team": 34 },
{ "week": "W2", "pro": 111, "team": 37 },
{ "week": "W3", "pro": 120, "team": 35 },
{ "week": "W4", "pro": 105, "team": 50 },
{ "week": "W5", "pro": 114, "team": 49 },
{ "week": "W6", "pro": 129, "team": 55 },
{ "week": "W7", "pro": 132, "team": 82 },
{ "week": "W8", "pro": 143, "team": 76 },
{ "week": "W9", "pro": 126, "team": 86 },
{ "week": "W10", "pro": 139, "team": 86 },
], "delta": 0.225 },
];
export function Example() {
return (
);
}
```
#### Previous period
A dashed series is a reference: drawn quietly, never counted in the headline.
```tsx
'use client';
import { LineChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "Sep 1–21", "data": [
{ "date": new Date('2026-09-01T00:00:00.000Z'), "revenue": 2180, "previous": 1950 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "revenue": 2340, "previous": 2050 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "revenue": 2110, "previous": 2020 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "revenue": 2670, "previous": 2140 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "revenue": 2510, "previous": 2220 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "revenue": 2880, "previous": 2300 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "revenue": 2750, "previous": 2250 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "revenue": 3090, "previous": 2470 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "revenue": 2870, "previous": 2390 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "revenue": 3360, "previous": 2680 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "revenue": 3190, "previous": 2760 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "revenue": 3520, "previous": 2840 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "revenue": 3440, "previous": 2920 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "revenue": 3710, "previous": 3060 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "revenue": 3580, "previous": 3010 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "revenue": 3960, "previous": 3180 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "revenue": 3820, "previous": 3120 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "revenue": 4150, "previous": 3300 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "revenue": 4030, "previous": 3260 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "revenue": 4420, "previous": 3410 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "revenue": 4310, "previous": 3380 },
], "delta": 0.156 },
{ "id": "previous", "label": "Aug 11–31", "data": [
{ "date": new Date('2026-08-11T00:00:00.000Z'), "revenue": 1831, "previous": 1638 },
{ "date": new Date('2026-08-12T00:00:00.000Z'), "revenue": 2169, "previous": 1900 },
{ "date": new Date('2026-08-13T00:00:00.000Z'), "revenue": 1870, "previous": 1791 },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "revenue": 2078, "previous": 1665 },
{ "date": new Date('2026-08-15T00:00:00.000Z'), "revenue": 1909, "previous": 1688 },
{ "date": new Date('2026-08-16T00:00:00.000Z'), "revenue": 2475, "previous": 1977 },
{ "date": new Date('2026-08-17T00:00:00.000Z'), "revenue": 2557, "previous": 2092 },
{ "date": new Date('2026-08-18T00:00:00.000Z'), "revenue": 2684, "previous": 2146 },
{ "date": new Date('2026-08-19T00:00:00.000Z'), "revenue": 2197, "previous": 1830 },
{ "date": new Date('2026-08-20T00:00:00.000Z'), "revenue": 2592, "previous": 2067 },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "revenue": 2800, "previous": 2423 },
{ "date": new Date('2026-08-22T00:00:00.000Z'), "revenue": 3269, "previous": 2638 },
{ "date": new Date('2026-08-23T00:00:00.000Z'), "revenue": 2923, "previous": 2481 },
{ "date": new Date('2026-08-24T00:00:00.000Z'), "revenue": 2806, "previous": 2315 },
{ "date": new Date('2026-08-25T00:00:00.000Z'), "revenue": 2812, "previous": 2365 },
{ "date": new Date('2026-08-26T00:00:00.000Z'), "revenue": 3542, "previous": 2845 },
{ "date": new Date('2026-08-27T00:00:00.000Z'), "revenue": 3528, "previous": 2882 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "revenue": 3445, "previous": 2740 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "revenue": 3027, "previous": 2449 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "revenue": 3546, "previous": 2736 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "revenue": 3916, "previous": 3071 },
], "delta": 0.07 },
];
export function Example() {
return (
);
}
```
#### Forecast with a range
The line turns dotted where measurements end, inside a band from `lower` to `upper`. The headline counts only measured days; hovering a projection says so.
```tsx
'use client';
import { LineChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This period", "data": [
{ "date": new Date('2026-09-01T00:00:00.000Z'), "revenue": 2180, "low": null, "high": null },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "revenue": 2340, "low": null, "high": null },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "revenue": 2110, "low": null, "high": null },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "revenue": 2670, "low": null, "high": null },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "revenue": 2510, "low": null, "high": null },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "revenue": 2880, "low": null, "high": null },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "revenue": 2750, "low": null, "high": null },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "revenue": 3090, "low": null, "high": null },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "revenue": 2870, "low": null, "high": null },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "revenue": 3360, "low": null, "high": null },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "revenue": 3190, "low": null, "high": null },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "revenue": 3520, "low": null, "high": null },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "revenue": 3440, "low": null, "high": null },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "revenue": 3710, "low": null, "high": null },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "revenue": 3580, "low": null, "high": null },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "revenue": 3960, "low": null, "high": null },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "revenue": 3820, "low": null, "high": null },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "revenue": 4150, "low": null, "high": null },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "revenue": 4030, "low": null, "high": null },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "revenue": 4420, "low": null, "high": null },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "revenue": 4310, "low": 4310, "high": 4310 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "revenue": 4480, "low": 4323, "high": 4614 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "revenue": 4560, "low": 4241, "high": 4834 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "revenue": 4610, "low": 4126, "high": 5025 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "revenue": 4700, "low": 4042, "high": 5264 },
{ "date": new Date('2026-09-26T00:00:00.000Z'), "revenue": 4760, "low": 3927, "high": 5474 },
{ "date": new Date('2026-09-27T00:00:00.000Z'), "revenue": 4850, "low": 3832, "high": 5723 },
{ "date": new Date('2026-09-28T00:00:00.000Z'), "revenue": 4920, "low": 3715, "high": 5953 },
] },
{ "id": "previous", "label": "Last period", "data": [
{ "date": new Date('2026-08-04T00:00:00.000Z'), "revenue": 1831, "low": null, "high": null },
{ "date": new Date('2026-08-05T00:00:00.000Z'), "revenue": 2169, "low": null, "high": null },
{ "date": new Date('2026-08-06T00:00:00.000Z'), "revenue": 1870, "low": null, "high": null },
{ "date": new Date('2026-08-07T00:00:00.000Z'), "revenue": 2078, "low": null, "high": null },
{ "date": new Date('2026-08-08T00:00:00.000Z'), "revenue": 1909, "low": null, "high": null },
{ "date": new Date('2026-08-09T00:00:00.000Z'), "revenue": 2475, "low": null, "high": null },
{ "date": new Date('2026-08-10T00:00:00.000Z'), "revenue": 2557, "low": null, "high": null },
{ "date": new Date('2026-08-11T00:00:00.000Z'), "revenue": 2684, "low": null, "high": null },
{ "date": new Date('2026-08-12T00:00:00.000Z'), "revenue": 2197, "low": null, "high": null },
{ "date": new Date('2026-08-13T00:00:00.000Z'), "revenue": 2592, "low": null, "high": null },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "revenue": 2800, "low": null, "high": null },
{ "date": new Date('2026-08-15T00:00:00.000Z'), "revenue": 3269, "low": null, "high": null },
{ "date": new Date('2026-08-16T00:00:00.000Z'), "revenue": 2923, "low": null, "high": null },
{ "date": new Date('2026-08-17T00:00:00.000Z'), "revenue": 2806, "low": null, "high": null },
{ "date": new Date('2026-08-18T00:00:00.000Z'), "revenue": 2812, "low": null, "high": null },
{ "date": new Date('2026-08-19T00:00:00.000Z'), "revenue": 3542, "low": null, "high": null },
{ "date": new Date('2026-08-20T00:00:00.000Z'), "revenue": 3528, "low": null, "high": null },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "revenue": 3445, "low": null, "high": null },
{ "date": new Date('2026-08-22T00:00:00.000Z'), "revenue": 3027, "low": null, "high": null },
{ "date": new Date('2026-08-23T00:00:00.000Z'), "revenue": 3546, "low": null, "high": null },
{ "date": new Date('2026-08-24T00:00:00.000Z'), "revenue": 3916, "low": 3916, "high": 3916 },
{ "date": new Date('2026-08-25T00:00:00.000Z'), "revenue": 4097, "low": 3953, "high": 4219 },
{ "date": new Date('2026-08-26T00:00:00.000Z'), "revenue": 3699, "low": 3440, "high": 3921 },
{ "date": new Date('2026-08-27T00:00:00.000Z'), "revenue": 3458, "low": 3095, "high": 3769 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "revenue": 3857, "low": 3317, "high": 4320 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "revenue": 4377, "low": 3611, "high": 5034 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "revenue": 4374, "low": 3456, "high": 5161 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "revenue": 3904, "low": 2948, "high": 4724 },
] },
];
export function Example() {
return (
);
}
```
#### Target to stay under
With `deltaTone="inverse"`, on target means at or below the line, and the hover chip turns red above it.
```tsx
'use client';
import { LineChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This period", "data": [
{ "hour": "00:00", "p50": 82, "p95": 210 },
{ "hour": "03:00", "p50": 76, "p95": 188 },
{ "hour": "06:00", "p50": 91, "p95": 236 },
{ "hour": "09:00", "p50": 128, "p95": 342 },
{ "hour": "12:00", "p50": 141, "p95": 388 },
{ "hour": "15:00", "p50": 136, "p95": 361 },
{ "hour": "18:00", "p50": 118, "p95": 309 },
{ "hour": "21:00", "p50": 97, "p95": 254 },
] },
{ "id": "previous", "label": "Last period", "data": [
{ "hour": "00:00", "p50": 69, "p95": 176 },
{ "hour": "03:00", "p50": 70, "p95": 174 },
{ "hour": "06:00", "p50": 81, "p95": 209 },
{ "hour": "09:00", "p50": 100, "p95": 266 },
{ "hour": "12:00", "p50": 107, "p95": 295 },
{ "hour": "15:00", "p50": 117, "p95": 310 },
{ "hour": "18:00", "p50": 110, "p95": 287 },
{ "hour": "21:00", "p50": 84, "p95": 221 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per x position, one numeric field per series.
const latency = [
{ hour: '00:00', p50: 82, p95: 210 },
{ hour: '03:00', p50: 76, p95: 188 },
];
```
Pass your rows as they are. `x` and each series `key` name fields on the row, and TypeScript rejects keys that don’t exist or aren’t numbers. By default the headline totals every series; use `aggregate` and `headlineSeries` when the numbers are rates or levels rather than counts. `null` is a gap, not zero.
### Period select
```tsx
```
### Hover
Hovering moves Lilt’s hover dots along every line. Move up and down and the y pill, the halo, and the matching tile follow the line nearest your pointer, even while a point is pinned. Up and Down keys do the same from the keyboard. Set `hover` to `tooltip` or `headline` for a different readout.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `data` (`Row[]`): One row per x position. Omit when using ranges.
- `x` (`key of Row`): Text, number, or Date field for the x axis.
- `series` (`{ key, label?, color?, dashed? }[]`): Numeric fields to plot, checked against your row type. Dashed series are references left out of the headline.
- `indexed` (`boolean`): Rebase each series to 100 at its first finite reading. Zero baselines are unindexable. Unitless output; defaults to the latest first-series headline. Forecast envelopes are omitted while indexed.
- `curve` (`'smooth' | 'linear' | 'step'`): Monotone spline, straight segments, or steps that hold each value.
- `points` (`boolean`): Mark every observation with a small dot.
- `baseline` (`'auto' | 'zero'`): Fit the y axis to the data (default) or start it at zero.
- `aggregate` (`'sum' | 'mean' | 'last' | 'max'`): How the headline and tiles summarize the period. Defaults to sum.
- `headlineSeries` (`key`): Make the headline follow one series instead of the total.
- `bleed` (`boolean`): Run lines to the card edges with a soft fade. Defaults to true.
- `depth` (`boolean`): Draws each line as a lit tube with a soft shadow along its exact path. Dashed references stay flat.
- `decimate` (`boolean`): Draw a long series from each pixel column’s first, last, lowest and highest point, so tens of thousands of points stay fast. Hover, tiles and exports still read every row. Defaults to true.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `delta` (`number`): Fractional change for the chip: 0.082 shows +8.2%.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `headline` (`number`): Resting headline. Defaults to the aggregate of non-reference series; dashed series are excluded.
- `range` (`string`): Static period label in the header.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the data.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `tiles` (`boolean`): Per-series value tiles. Defaults to true; false hides the legend.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): False removes the legend without changing the data. How the legend under the plot lays out: value tiles (default), a compact inline key, list rows, tinted pills, or bars that also draw each value against the largest.
- `legendSwatch` (`'square' | 'dot' | 'line'`): The mark beside each legend label. Defaults to a rounded square.
- `height` (`number`): Plot height in pixels. Defaults to 240.
- `axis` (`'minimal' | 'dots' | 'inline' | 'ruler' | 'classic' | 'segmented' | { x, y }`): Axis preset. Minimal (default) labels only the x ends and has no grid. Set one per axis with `{ x, y }`; a segmented axis can take a `gradient` to read as a range.
- `hover` (`'pills' | 'tooltip' | 'strip' | 'headline'`): The one readout for the hovered point: pills on the axes (default), a tooltip with every series, a strip docked above the plot, or the headline and tiles alone.
- `hoverStyle` (`'soft' | 'solid' | 'accent'`): How the pills or tooltip look. Soft (default) is surface glass; accent tints it with the hovered series.
- `pillSeries` (`'nearest' | 'total' | key`): Which series the y pill reads and the tooltip leads with. Nearest (default) follows the pointer.
- `pillPosition` (`'auto' | 'mark' | 'axis'`): Where the value pill sits: above the hovered mark, or on the y axis. Auto picks mark when there are no y labels.
- `tooltipIndicator` (`'square' | 'dot' | 'line'`): Series marker on each tooltip row, with hover="tooltip". Square by default.
- `background` (`'dots' | 'grid' | 'lines' | 'none'`): Texture behind the marks. Dots by default, with a hover spotlight.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `axisInset` (`number`): Padding between the plot edges and axis labels or pills.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `compare` (`boolean | 'headline' | 'badge'`): Drag across the plot to compare two points in time. True or headline reads the change in the headline; badge reads it in the card’s tab and leaves the headline at rest.
- `target` (`number | { value, label? }`): A goal each point should reach: a labeled line, a “vs target” chip on hover, and a count of points on target at rest.
- `forecast` (`{ from, lower?, upper?, label?, bands?: { lower, upper, label }[] }`): Rows from `from` onward are projections: dotted and excluded from the headline. Supply lower/upper for one envelope, or bands ordered widest to narrowest for a fan on Line and unstacked Area. Every bound is inspectable; no forecast is estimated.
- `sync` (`string`): Link hover and pins with every card that uses the same name, matched by x value. A click pins them all, with a ghost pin on the others; Alt-click pins one card only.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `formatAxisValue` (`(value: number) => string`): Custom compact axis value text.
- `formatX` (`(value: string | number | Date) => string`): Custom x label text.
- `xType` (`'category' | 'number' | 'time'`): Override inferred x type. Use time for numeric Unix timestamps in milliseconds.
- `spotlight` (`boolean`): Highlight the inspected position in the plot background. Defaults to true.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
- `pillValue` (`'series' | 'stack'`): Read an individual series value (default) or its stacked height. Has no effect when the card has no stacked series.
## Combo chart: `ComboChartCard`
Bring amounts and trends together with bars and lines. Docs: https://liltui.vercel.app/charts/combo
```tsx
import { ComboChartCard } from '@lilt-ui/charts';
```
### Complete examples
#### Combo chart card
```tsx
'use client';
import { ComboChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "year", "label": "This year", "data": [
{ "month": "Jan", "revenue": 42000, "costs": 31000, "budget": 44000, "margin": 0.262 },
{ "month": "Feb", "revenue": 46000, "costs": 33000, "budget": 46000, "margin": 0.283 },
{ "month": "Mar", "revenue": 51000, "costs": 36000, "budget": 48000, "margin": 0.294 },
{ "month": "Apr", "revenue": 49000, "costs": 35000, "budget": 50000, "margin": 0.286 },
{ "month": "May", "revenue": 55000, "costs": 37000, "budget": 53000, "margin": 0.327 },
{ "month": "Jun", "revenue": 61000, "costs": 40000, "budget": 56000, "margin": 0.344 },
{ "month": "Jul", "revenue": 58000, "costs": 39000, "budget": 59000, "margin": 0.328 },
{ "month": "Aug", "revenue": 64000, "costs": 41000, "budget": 62000, "margin": 0.359 },
{ "month": "Sep", "revenue": 70000, "costs": 44000, "budget": 65000, "margin": 0.371 },
{ "month": "Oct", "revenue": 68000, "costs": 43000, "budget": 68000, "margin": 0.368 },
{ "month": "Nov", "revenue": 75000, "costs": 46000, "budget": 72000, "margin": 0.387 },
{ "month": "Dec", "revenue": 83000, "costs": 49000, "budget": 76000, "margin": 0.41 },
], "delta": 0.212 },
{ "id": "last-year", "label": "Last year", "data": [
{ "month": "Jan", "revenue": 34000, "costs": 27000, "budget": 35000, "margin": 0.206 },
{ "month": "Feb", "revenue": 36000, "costs": 28000, "budget": 37000, "margin": 0.222 },
{ "month": "Mar", "revenue": 39000, "costs": 30000, "budget": 39000, "margin": 0.231 },
{ "month": "Apr", "revenue": 38000, "costs": 30000, "budget": 41000, "margin": 0.211 },
{ "month": "May", "revenue": 42000, "costs": 32000, "budget": 43000, "margin": 0.238 },
{ "month": "Jun", "revenue": 45000, "costs": 34000, "budget": 45000, "margin": 0.244 },
{ "month": "Jul", "revenue": 44000, "costs": 34000, "budget": 47000, "margin": 0.227 },
{ "month": "Aug", "revenue": 48000, "costs": 36000, "budget": 49000, "margin": 0.25 },
{ "month": "Sep", "revenue": 51000, "costs": 38000, "budget": 51000, "margin": 0.255 },
{ "month": "Oct", "revenue": 50000, "costs": 37000, "budget": 53000, "margin": 0.26 },
{ "month": "Nov", "revenue": 55000, "costs": 40000, "budget": 55000, "margin": 0.273 },
{ "month": "Dec", "revenue": 60000, "costs": 43000, "budget": 58000, "margin": 0.283 },
], "delta": 0.094 },
];
export function Example() {
return (
);
}
```
#### A rate on its own scale
Margin is a percentage, so `lineScale="own"` fits it to its own scale. Its tile averages the year, and its pill and tile use its own `valueFormat`.
```tsx
'use client';
import { ComboChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This year", "data": [
{ "month": "Jan", "revenue": 42000, "costs": 31000, "budget": 44000, "margin": 0.262 },
{ "month": "Feb", "revenue": 46000, "costs": 33000, "budget": 46000, "margin": 0.283 },
{ "month": "Mar", "revenue": 51000, "costs": 36000, "budget": 48000, "margin": 0.294 },
{ "month": "Apr", "revenue": 49000, "costs": 35000, "budget": 50000, "margin": 0.286 },
{ "month": "May", "revenue": 55000, "costs": 37000, "budget": 53000, "margin": 0.327 },
{ "month": "Jun", "revenue": 61000, "costs": 40000, "budget": 56000, "margin": 0.344 },
{ "month": "Jul", "revenue": 58000, "costs": 39000, "budget": 59000, "margin": 0.328 },
{ "month": "Aug", "revenue": 64000, "costs": 41000, "budget": 62000, "margin": 0.359 },
{ "month": "Sep", "revenue": 70000, "costs": 44000, "budget": 65000, "margin": 0.371 },
{ "month": "Oct", "revenue": 68000, "costs": 43000, "budget": 68000, "margin": 0.368 },
{ "month": "Nov", "revenue": 75000, "costs": 46000, "budget": 72000, "margin": 0.387 },
{ "month": "Dec", "revenue": 83000, "costs": 49000, "budget": 76000, "margin": 0.41 },
], "delta": 0.212 },
{ "id": "previous", "label": "Last year", "data": [
{ "month": "Jan", "revenue": 35280, "costs": 26040, "budget": 36960, "margin": 0.22 },
{ "month": "Feb", "revenue": 42629, "costs": 30582, "budget": 42629, "margin": 0.26 },
{ "month": "Mar", "revenue": 45206, "costs": 31910, "budget": 42547, "margin": 0.26 },
{ "month": "Apr", "revenue": 38127, "costs": 27234, "budget": 38905, "margin": 0.22 },
{ "month": "May", "revenue": 41827, "costs": 28138, "budget": 40306, "margin": 0.25 },
{ "month": "Jun", "revenue": 52421, "costs": 34374, "budget": 48124, "margin": 0.3 },
{ "month": "Jul", "revenue": 53932, "costs": 36265, "budget": 54862, "margin": 0.3 },
{ "month": "Aug", "revenue": 55598, "costs": 35617, "budget": 53861, "margin": 0.31 },
{ "month": "Sep", "revenue": 53585, "costs": 33682, "budget": 49757, "margin": 0.28 },
{ "month": "Oct", "revenue": 52457, "costs": 33171, "budget": 52457, "margin": 0.28 },
{ "month": "Nov", "revenue": 65836, "costs": 40379, "budget": 63203, "margin": 0.34 },
{ "month": "Dec", "revenue": 77091, "costs": 45512, "budget": 70590, "margin": 0.38 },
], "delta": 0.095 },
];
export function Example() {
return (
);
}
```
#### Grouped bars and a line
Revenue and costs side by side, with margin tracing the gap between them.
```tsx
'use client';
import { ComboChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This year", "data": [
{ "month": "Jan", "revenue": 42000, "costs": 31000, "budget": 44000, "margin": 0.262 },
{ "month": "Feb", "revenue": 46000, "costs": 33000, "budget": 46000, "margin": 0.283 },
{ "month": "Mar", "revenue": 51000, "costs": 36000, "budget": 48000, "margin": 0.294 },
{ "month": "Apr", "revenue": 49000, "costs": 35000, "budget": 50000, "margin": 0.286 },
{ "month": "May", "revenue": 55000, "costs": 37000, "budget": 53000, "margin": 0.327 },
{ "month": "Jun", "revenue": 61000, "costs": 40000, "budget": 56000, "margin": 0.344 },
{ "month": "Jul", "revenue": 58000, "costs": 39000, "budget": 59000, "margin": 0.328 },
{ "month": "Aug", "revenue": 64000, "costs": 41000, "budget": 62000, "margin": 0.359 },
{ "month": "Sep", "revenue": 70000, "costs": 44000, "budget": 65000, "margin": 0.371 },
{ "month": "Oct", "revenue": 68000, "costs": 43000, "budget": 68000, "margin": 0.368 },
{ "month": "Nov", "revenue": 75000, "costs": 46000, "budget": 72000, "margin": 0.387 },
{ "month": "Dec", "revenue": 83000, "costs": 49000, "budget": 76000, "margin": 0.41 },
] },
{ "id": "previous", "label": "Last year", "data": [
{ "month": "Jan", "revenue": 35280, "costs": 26040, "budget": 36960, "margin": 0.22 },
{ "month": "Feb", "revenue": 42629, "costs": 30582, "budget": 42629, "margin": 0.26 },
{ "month": "Mar", "revenue": 45206, "costs": 31910, "budget": 42547, "margin": 0.26 },
{ "month": "Apr", "revenue": 38127, "costs": 27234, "budget": 38905, "margin": 0.22 },
{ "month": "May", "revenue": 41827, "costs": 28138, "budget": 40306, "margin": 0.25 },
{ "month": "Jun", "revenue": 52421, "costs": 34374, "budget": 48124, "margin": 0.3 },
{ "month": "Jul", "revenue": 53932, "costs": 36265, "budget": 54862, "margin": 0.3 },
{ "month": "Aug", "revenue": 55598, "costs": 35617, "budget": 53861, "margin": 0.31 },
{ "month": "Sep", "revenue": 53585, "costs": 33682, "budget": 49757, "margin": 0.28 },
{ "month": "Oct", "revenue": 52457, "costs": 33171, "budget": 52457, "margin": 0.28 },
{ "month": "Nov", "revenue": 65836, "costs": 40379, "budget": 63203, "margin": 0.34 },
{ "month": "Dec", "revenue": 77091, "costs": 45512, "budget": 70590, "margin": 0.38 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per x position, one numeric field per bar or line.
const finance = [
{ month: 'Jan', revenue: 42000, budget: 44000, margin: 0.262 },
{ month: 'Feb', revenue: 46000, budget: 46000, margin: 0.283 },
];
```
Pass your rows as they are; `x`, and every `key` in `bars` and `lines`, are checked against your row type. The headline totals the bars only, since a budget or a rate is not part of the amount. Each series gets a tile. `null` is an empty bar slot or a gap in the line, never zero.
### Period select
```tsx
```
### Hover
Hovering a month lifts its bars and puts Lilt’s hover dot on each line. The pill reads the bar under the pointer, or the line when the pointer comes close to it, even while a month is pinned. The headline counts to that month’s bar total and every tile shows its value there. Set `hover` to `tooltip` or `headline` for a different readout.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `data` (`Row[]`): One row per x position. Omit when using ranges.
- `x` (`key of Row`): Text, number, or Date field for the x axis.
- `bars` (`{ key, label?, color? }[]`): Numeric fields drawn as grouped bars. They make up the headline.
- `lines` (`{ key, label?, color?, dashed?, valueFormat?, aggregate? }[]`): Numeric fields drawn over the bars, e.g. a budget, a forecast, or a rate.
- `lineScale` (`'shared' | 'own'`): Shared (default) compares lines against bar heights directly. Own fits lines to their own scale for a different unit, labelled on the right with the same gridlines.
- `radius` (`number`): Corner radius of each bar’s value end. Defaults to 6.
- `barWidth` (`number`): Maximum bar width in pixels.
- `barStyle` (`'solid' | 'segmented' | 'needle' | 'gradient' | 'outline' | 'isometric'`): How bars are drawn.
- `curve` (`'smooth' | 'linear'`): Line shape. Smooth by default.
- `points` (`boolean`): Dots on line observations. On by default.
- `aggregate` (`'sum' | 'mean' | 'last' | 'max'`): How the headline and tiles summarize the period. Lines on their own scale average by default.
- `depth` (`boolean`): Bars become solid blocks and lines lit tubes. Both keep their exact values.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `delta` (`number`): Fractional change for the chip: 0.082 shows +8.2%.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `headline` (`number`): Resting headline. Defaults to the aggregate of non-reference series; dashed series are excluded.
- `range` (`string`): Static period label in the header.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the data.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `tiles` (`boolean`): Per-series value tiles. Defaults to true; false hides the legend.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): False removes the legend without changing the data. How the legend under the plot lays out: value tiles (default), a compact inline key, list rows, tinted pills, or bars that also draw each value against the largest.
- `legendSwatch` (`'square' | 'dot' | 'line'`): The mark beside each legend label. Defaults to a rounded square.
- `height` (`number`): Plot height in pixels. Defaults to 240.
- `axis` (`'minimal' | 'dots' | 'inline' | 'ruler' | 'classic' | 'segmented' | { x, y }`): Axis preset. Minimal (default) labels only the x ends and has no grid. Set one per axis with `{ x, y }`; a segmented axis can take a `gradient` to read as a range.
- `hover` (`'pills' | 'tooltip' | 'strip' | 'headline'`): The one readout for the hovered point: pills on the axes (default), a tooltip with every series, a strip docked above the plot, or the headline and tiles alone.
- `hoverStyle` (`'soft' | 'solid' | 'accent'`): How the pills or tooltip look. Soft (default) is surface glass; accent tints it with the hovered series.
- `pillSeries` (`'nearest' | 'total' | key`): Which series the y pill reads and the tooltip leads with. Nearest (default) follows the pointer.
- `pillPosition` (`'auto' | 'mark' | 'axis'`): Where the value pill sits: above the hovered mark, or on the y axis. Auto picks mark when there are no y labels.
- `tooltipIndicator` (`'square' | 'dot' | 'line'`): Series marker on each tooltip row, with hover="tooltip". Square by default.
- `background` (`'dots' | 'grid' | 'lines' | 'none'`): Texture behind the marks. Dots by default, with a hover spotlight.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `axisInset` (`number`): Padding between the plot edges and axis labels or pills.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `compare` (`boolean | 'headline' | 'badge'`): Drag across the plot to compare two points in time. True or headline reads the change in the headline; badge reads it in the card’s tab and leaves the headline at rest.
- `target` (`number | { value, label? }`): A goal each point should reach: a labeled line, a “vs target” chip on hover, and a count of points on target at rest.
- `forecast` (`{ from, lower?, upper?, label?, bands?: { lower, upper, label }[] }`): Rows from `from` onward are projections: dotted and excluded from the headline. Supply lower/upper for one envelope, or bands ordered widest to narrowest for a fan on Line and unstacked Area. Every bound is inspectable; no forecast is estimated.
- `sync` (`string`): Link hover and pins with every card that uses the same name, matched by x value. A click pins them all, with a ghost pin on the others; Alt-click pins one card only.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `headlineSeries` (`key of Row`): Numeric series whose value drives the headline instead of the combined total.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `formatAxisValue` (`(value: number) => string`): Custom compact axis value text.
- `formatX` (`(value: string | number | Date) => string`): Custom x label text.
- `xType` (`'category' | 'number' | 'time'`): Override inferred x type. Use time for numeric Unix timestamps in milliseconds.
- `spotlight` (`boolean`): Highlight the inspected position in the plot background. Defaults to true.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
- `stack` (`boolean | 'percent'`): Stack the bar series with true or show percentage shares with percent. Lines remain unstacked.
- `corners` (`'end' | 'all'`): Round the value end (default), or all bar corners.
- `tracks` (`boolean`): Draw full-height tracks behind bars or stacks. Defaults to false.
- `decimate` (`boolean`): Defaults to true. Line and Area marks retain at most four observations per pixel column. Other marks draw every row; inspection and summaries always read the full data.
- `bleed` (`boolean`): Let marks reach the card edges with a soft fade.
## Bar chart: `BarChartCard`
Compare amounts side by side, stacked, or as shares. Docs: https://liltui.vercel.app/charts/bar
```tsx
import { BarChartCard } from '@lilt-ui/charts';
```
### Complete examples
#### Bar chart card
```tsx
'use client';
import { BarChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "year", "label": "This year", "data": [
{ "month": "Jan", "online": 420, "retail": 310, "target": 700 },
{ "month": "Feb", "online": 460, "retail": 290, "target": 720 },
{ "month": "Mar", "online": 510, "retail": 330, "target": 760 },
{ "month": "Apr", "online": 480, "retail": 350, "target": 800 },
{ "month": "May", "online": 560, "retail": 340, "target": 840 },
{ "month": "Jun", "online": 620, "retail": 380, "target": 880 },
{ "month": "Jul", "online": 690, "retail": 400, "target": 920 },
{ "month": "Aug", "online": 650, "retail": 390, "target": 960 },
{ "month": "Sep", "online": 720, "retail": 420, "target": 1000 },
{ "month": "Oct", "online": 780, "retail": 450, "target": 1040 },
{ "month": "Nov", "online": 860, "retail": 510, "target": 1100 },
{ "month": "Dec", "online": 980, "retail": 620, "target": 1200 },
], "delta": 0.143 },
{ "id": "six-months", "label": "Last 6 months", "data": [
{ "month": "Jul", "online": 690, "retail": 400, "target": 920 },
{ "month": "Aug", "online": 650, "retail": 390, "target": 960 },
{ "month": "Sep", "online": 720, "retail": 420, "target": 1000 },
{ "month": "Oct", "online": 780, "retail": 450, "target": 1040 },
{ "month": "Nov", "online": 860, "retail": 510, "target": 1100 },
{ "month": "Dec", "online": 980, "retail": 620, "target": 1200 },
], "delta": 0.088 },
{ "id": "last-year", "label": "Last year", "data": [
{ "month": "Jan", "online": 360, "retail": 300, "target": 640 },
{ "month": "Feb", "online": 380, "retail": 280, "target": 660 },
{ "month": "Mar", "online": 420, "retail": 300, "target": 680 },
{ "month": "Apr", "online": 410, "retail": 320, "target": 700 },
{ "month": "May", "online": 470, "retail": 320, "target": 740 },
{ "month": "Jun", "online": 520, "retail": 340, "target": 780 },
{ "month": "Jul", "online": 560, "retail": 360, "target": 820 },
{ "month": "Aug", "online": 560, "retail": 350, "target": 860 },
{ "month": "Sep", "online": 600, "retail": 380, "target": 900 },
{ "month": "Oct", "online": 640, "retail": 400, "target": 940 },
{ "month": "Nov", "online": 700, "retail": 450, "target": 980 },
{ "month": "Dec", "online": 810, "retail": 540, "target": 1040 },
], "delta": 0.071 },
];
export function Example() {
return (
);
}
```
#### Team sentiment
Survey counts stack on either side of neutral. Neutral responses split around zero, and missing contributions leave the row incomplete rather than becoming zero.
```tsx
'use client';
import { DivergingBarCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const sentimentResponses = [
{ "team": "Product", "disagree": 14, "unsure": 10, "agree": 42, "strongly": 34 },
{ "team": "Design", "disagree": 8, "unsure": 16, "agree": 48, "strongly": 28 },
{ "team": "Growth", "disagree": 24, "unsure": 18, "agree": 36, "strongly": 22 },
{ "team": "Support", "disagree": 12, "unsure": 14, "agree": 32, "strongly": 42 },
{ "team": "Ops", "disagree": 20, "unsure": 12, "agree": 44, "strongly": 24 },
];
export function Example() {
return (
);
}
```
#### Thirty days of sales
A month of daily, stacked sales built from small cells like a level meter. Stacked cells run straight across the color change, and the top cell is trimmed to the exact value.
```tsx
'use client';
import { BarChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "Last 30 days", "data": [
{ "date": new Date('2026-03-22T00:00:00.000Z'), "newUsers": 4200, "existing": 9800 },
{ "date": new Date('2026-03-23T00:00:00.000Z'), "newUsers": 5600, "existing": 10400 },
{ "date": new Date('2026-03-24T00:00:00.000Z'), "newUsers": 4800, "existing": 8100 },
{ "date": new Date('2026-03-25T00:00:00.000Z'), "newUsers": 4300, "existing": 7200 },
{ "date": new Date('2026-03-26T00:00:00.000Z'), "newUsers": 5100, "existing": 9300 },
{ "date": new Date('2026-03-27T00:00:00.000Z'), "newUsers": 4900, "existing": 10100 },
{ "date": new Date('2026-03-28T00:00:00.000Z'), "newUsers": 3400, "existing": 6800 },
{ "date": new Date('2026-03-29T00:00:00.000Z'), "newUsers": 3100, "existing": 5700 },
{ "date": new Date('2026-03-30T00:00:00.000Z'), "newUsers": 5800, "existing": 9100 },
{ "date": new Date('2026-03-31T00:00:00.000Z'), "newUsers": 5200, "existing": 8300 },
{ "date": new Date('2026-04-01T00:00:00.000Z'), "newUsers": 4400, "existing": 7200 },
{ "date": new Date('2026-04-02T00:00:00.000Z'), "newUsers": 5000, "existing": 9900 },
{ "date": new Date('2026-04-03T00:00:00.000Z'), "newUsers": 4700, "existing": 10200 },
{ "date": new Date('2026-04-04T00:00:00.000Z'), "newUsers": 4100, "existing": 6700 },
{ "date": new Date('2026-04-05T00:00:00.000Z'), "newUsers": 3600, "existing": 5300 },
{ "date": new Date('2026-04-06T00:00:00.000Z'), "newUsers": 6400, "existing": 11400 },
{ "date": new Date('2026-04-07T00:00:00.000Z'), "newUsers": 5900, "existing": 9600 },
{ "date": new Date('2026-04-08T00:00:00.000Z'), "newUsers": 4800, "existing": 8000 },
{ "date": new Date('2026-04-09T00:00:00.000Z'), "newUsers": 4500, "existing": 11500 },
{ "date": new Date('2026-04-10T00:00:00.000Z'), "newUsers": 5700, "existing": 10200 },
{ "date": new Date('2026-04-11T00:00:00.000Z'), "newUsers": 4600, "existing": 7600 },
{ "date": new Date('2026-04-12T00:00:00.000Z'), "newUsers": 4300, "existing": 5900 },
{ "date": new Date('2026-04-13T00:00:00.000Z'), "newUsers": 6200, "existing": 11600 },
{ "date": new Date('2026-04-14T00:00:00.000Z'), "newUsers": 5800, "existing": 10900 },
{ "date": new Date('2026-04-15T00:00:00.000Z'), "newUsers": 5400, "existing": 9800 },
{ "date": new Date('2026-04-16T00:00:00.000Z'), "newUsers": 5100, "existing": 8600 },
{ "date": new Date('2026-04-17T00:00:00.000Z'), "newUsers": 5900, "existing": 10400 },
{ "date": new Date('2026-04-18T00:00:00.000Z'), "newUsers": 5200, "existing": 9900 },
{ "date": new Date('2026-04-19T00:00:00.000Z'), "newUsers": 3900, "existing": 6600 },
{ "date": new Date('2026-04-20T00:00:00.000Z'), "newUsers": 5600, "existing": 9100 },
], "delta": 0.015 },
{ "id": "previous", "label": "Previous 30 days", "data": [
{ "date": new Date('2026-02-20T00:00:00.000Z'), "newUsers": 3528, "existing": 8232 },
{ "date": new Date('2026-02-21T00:00:00.000Z'), "newUsers": 5190, "existing": 9638 },
{ "date": new Date('2026-02-22T00:00:00.000Z'), "newUsers": 4255, "existing": 7180 },
{ "date": new Date('2026-02-23T00:00:00.000Z'), "newUsers": 3346, "existing": 5602 },
{ "date": new Date('2026-02-24T00:00:00.000Z'), "newUsers": 3878, "existing": 7073 },
{ "date": new Date('2026-02-25T00:00:00.000Z'), "newUsers": 4211, "existing": 8680 },
{ "date": new Date('2026-02-26T00:00:00.000Z'), "newUsers": 3162, "existing": 6323 },
{ "date": new Date('2026-02-27T00:00:00.000Z'), "newUsers": 2693, "existing": 4952 },
{ "date": new Date('2026-02-28T00:00:00.000Z'), "newUsers": 4440, "existing": 6966 },
{ "date": new Date('2026-03-01T00:00:00.000Z'), "newUsers": 4011, "existing": 6403 },
{ "date": new Date('2026-03-02T00:00:00.000Z'), "newUsers": 3862, "existing": 6320 },
{ "date": new Date('2026-03-03T00:00:00.000Z'), "newUsers": 4644, "existing": 9195 },
{ "date": new Date('2026-03-04T00:00:00.000Z'), "newUsers": 3994, "existing": 8667 },
{ "date": new Date('2026-03-05T00:00:00.000Z'), "newUsers": 3101, "existing": 5068 },
{ "date": new Date('2026-03-06T00:00:00.000Z'), "newUsers": 2828, "existing": 4163 },
{ "date": new Date('2026-03-07T00:00:00.000Z'), "newUsers": 5725, "existing": 10197 },
{ "date": new Date('2026-03-08T00:00:00.000Z'), "newUsers": 5449, "existing": 8866 },
{ "date": new Date('2026-03-09T00:00:00.000Z'), "newUsers": 3985, "existing": 6642 },
{ "date": new Date('2026-03-10T00:00:00.000Z'), "newUsers": 3380, "existing": 8639 },
{ "date": new Date('2026-03-11T00:00:00.000Z'), "newUsers": 4573, "existing": 8183 },
{ "date": new Date('2026-03-12T00:00:00.000Z'), "newUsers": 4180, "existing": 6906 },
{ "date": new Date('2026-03-13T00:00:00.000Z'), "newUsers": 3932, "existing": 5395 },
{ "date": new Date('2026-03-14T00:00:00.000Z'), "newUsers": 5029, "existing": 9410 },
{ "date": new Date('2026-03-15T00:00:00.000Z'), "newUsers": 4351, "existing": 8176 },
{ "date": new Date('2026-03-16T00:00:00.000Z'), "newUsers": 4432, "existing": 8043 },
{ "date": new Date('2026-03-17T00:00:00.000Z'), "newUsers": 4690, "existing": 7908 },
{ "date": new Date('2026-03-18T00:00:00.000Z'), "newUsers": 5321, "existing": 9379 },
{ "date": new Date('2026-03-19T00:00:00.000Z'), "newUsers": 4126, "existing": 7856 },
{ "date": new Date('2026-03-20T00:00:00.000Z'), "newUsers": 2938, "existing": 4972 },
{ "date": new Date('2026-03-21T00:00:00.000Z'), "newUsers": 4704, "existing": 7645 },
], "delta": 0.007 },
];
export function Example() {
return (
);
}
```
#### A year at a glance
Thin needles keep twelve months quiet. The one you hover expands into a full bar with its value above it.
```tsx
'use client';
import { BarChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This year", "data": [
{ "month": "Jan", "revenue": 28400 },
{ "month": "Feb", "revenue": 84600 },
{ "month": "Mar", "revenue": 49200 },
{ "month": "Apr", "revenue": 61800 },
{ "month": "May", "revenue": 38700 },
{ "month": "Jun", "revenue": 74300 },
{ "month": "Jul", "revenue": 36100 },
{ "month": "Aug", "revenue": 92500 },
{ "month": "Sep", "revenue": 64800 },
{ "month": "Oct", "revenue": 49100 },
{ "month": "Nov", "revenue": 77900 },
{ "month": "Dec", "revenue": 70200 },
], "delta": 0.052 },
{ "id": "previous", "label": "Last year", "data": [
{ "month": "Jan", "revenue": 23856 },
{ "month": "Feb", "revenue": 78401 },
{ "month": "Mar", "revenue": 43611 },
{ "month": "Apr", "revenue": 48087 },
{ "month": "May", "revenue": 29431 },
{ "month": "Jun", "revenue": 63851 },
{ "month": "Jul", "revenue": 33568 },
{ "month": "Aug", "revenue": 80356 },
{ "month": "Sep", "revenue": 49604 },
{ "month": "Oct", "revenue": 37877 },
{ "month": "Nov", "revenue": 68382 },
{ "month": "Dec", "revenue": 65202 },
], "delta": 0.023 },
];
export function Example() {
return (
);
}
```
#### By category
Put a text field on `x` and every bar gets its name. Here, revenue by acquisition channel, each bar fading toward its baseline.
```tsx
'use client';
import { BarChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "Sep 2026", "data": [
{ "channel": "Organic search", "revenue": 42800 },
{ "channel": "Direct", "revenue": 24100 },
{ "channel": "Paid social", "revenue": 31500 },
{ "channel": "Email", "revenue": 18200 },
{ "channel": "Referral", "revenue": 12600 },
] },
{ "id": "previous", "label": "Aug 2026", "data": [
{ "channel": "Organic search", "revenue": 35952 },
{ "channel": "Direct", "revenue": 22334 },
{ "channel": "Paid social", "revenue": 27921 },
{ "channel": "Email", "revenue": 14161 },
{ "channel": "Referral", "revenue": 9582 },
] },
];
export function Example() {
return (
);
}
```
#### A daily goal
A single `target` value draws a labeled line across every bar and counts the days that reach it, over rounded bars on quiet lanes.
```tsx
'use client';
import { BarChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This week", "data": [
{ "day": "Mon", "earnings": 3420 },
{ "day": "Tue", "earnings": 4180 },
{ "day": "Wed", "earnings": 3860 },
{ "day": "Thu", "earnings": 5240 },
{ "day": "Fri", "earnings": 6120 },
{ "day": "Sat", "earnings": 4470 },
{ "day": "Sun", "earnings": 2980 },
] },
{ "id": "previous", "label": "Last week", "data": [
{ "day": "Mon", "earnings": 2873 },
{ "day": "Tue", "earnings": 3874 },
{ "day": "Wed", "earnings": 3421 },
{ "day": "Thu", "earnings": 4077 },
{ "day": "Fri", "earnings": 4654 },
{ "day": "Sat", "earnings": 3841 },
{ "day": "Sun", "earnings": 2771 },
] },
];
export function Example() {
return (
);
}
```
#### Against a target
A dashed target series stays a line over the stack on the same scale, so you see which months cleared it. Each channel is its own rounded block over one lane per month.
```tsx
'use client';
import { BarChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This year", "data": [
{ "month": "Jan", "online": 420, "retail": 310, "target": 700 },
{ "month": "Feb", "online": 460, "retail": 290, "target": 720 },
{ "month": "Mar", "online": 510, "retail": 330, "target": 760 },
{ "month": "Apr", "online": 480, "retail": 350, "target": 800 },
{ "month": "May", "online": 560, "retail": 340, "target": 840 },
{ "month": "Jun", "online": 620, "retail": 380, "target": 880 },
{ "month": "Jul", "online": 690, "retail": 400, "target": 920 },
{ "month": "Aug", "online": 650, "retail": 390, "target": 960 },
{ "month": "Sep", "online": 720, "retail": 420, "target": 1000 },
{ "month": "Oct", "online": 780, "retail": 450, "target": 1040 },
{ "month": "Nov", "online": 860, "retail": 510, "target": 1100 },
{ "month": "Dec", "online": 980, "retail": 620, "target": 1200 },
], "delta": 0.143 },
{ "id": "previous", "label": "Last year", "data": [
{ "month": "Jan", "online": 353, "retail": 260, "target": 588 },
{ "month": "Feb", "online": 426, "retail": 269, "target": 667 },
{ "month": "Mar", "online": 452, "retail": 293, "target": 674 },
{ "month": "Apr", "online": 373, "retail": 272, "target": 622 },
{ "month": "May", "online": 426, "retail": 259, "target": 639 },
{ "month": "Jun", "online": 533, "retail": 327, "target": 756 },
{ "month": "Jul", "online": 642, "retail": 372, "target": 855 },
{ "month": "Aug", "online": 565, "retail": 339, "target": 834 },
{ "month": "Sep", "online": 551, "retail": 322, "target": 765 },
{ "month": "Oct", "online": 602, "retail": 347, "target": 802 },
{ "month": "Nov", "online": 755, "retail": 448, "target": 966 },
{ "month": "Dec", "online": 910, "retail": 576, "target": 1115 },
], "delta": 0.064 },
];
export function Example() {
return (
);
}
```
#### Projected months
Months from `forecast.from` onward draw dotted and stay out of the total until they are real.
```tsx
'use client';
import { BarChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This year", "data": [
{ "month": "Jan", "online": 420, "retail": 310, "target": 700 },
{ "month": "Feb", "online": 460, "retail": 290, "target": 720 },
{ "month": "Mar", "online": 510, "retail": 330, "target": 760 },
{ "month": "Apr", "online": 480, "retail": 350, "target": 800 },
{ "month": "May", "online": 560, "retail": 340, "target": 840 },
{ "month": "Jun", "online": 620, "retail": 380, "target": 880 },
{ "month": "Jul", "online": 690, "retail": 400, "target": 920 },
{ "month": "Aug", "online": 650, "retail": 390, "target": 960 },
{ "month": "Sep", "online": 720, "retail": 420, "target": 1000 },
{ "month": "Oct", "online": 780, "retail": 450, "target": 1040 },
{ "month": "Nov", "online": 860, "retail": 510, "target": 1100 },
{ "month": "Dec", "online": 980, "retail": 620, "target": 1200 },
] },
{ "id": "previous", "label": "Last year", "data": [
{ "month": "Jan", "online": 353, "retail": 260, "target": 588 },
{ "month": "Feb", "online": 426, "retail": 269, "target": 667 },
{ "month": "Mar", "online": 452, "retail": 293, "target": 674 },
{ "month": "Apr", "online": 373, "retail": 272, "target": 622 },
{ "month": "May", "online": 426, "retail": 259, "target": 639 },
{ "month": "Jun", "online": 533, "retail": 327, "target": 756 },
{ "month": "Jul", "online": 642, "retail": 372, "target": 855 },
{ "month": "Aug", "online": 565, "retail": 339, "target": 834 },
{ "month": "Sep", "online": 551, "retail": 322, "target": 765 },
{ "month": "Oct", "online": 602, "retail": 347, "target": 802 },
{ "month": "Nov", "online": 755, "retail": 448, "target": 966 },
{ "month": "Dec", "online": 910, "retail": 576, "target": 1115 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per x position, one numeric field per series.
const orders = [
{ month: 'Jan', online: 420, retail: 310, target: 700 },
{ month: 'Feb', online: 460, retail: 290, target: 720 },
];
```
Pass your rows as they are. `x` and each series `key` name fields on the row, and TypeScript rejects keys that don’t exist or aren’t numbers. A dashed series is always a reference line over the bars, grouped or stacked, and stays out of the headline. `null` leaves an empty slot, not a zero bar. With `stack="percent"`, each complete period fills to 100% and the headline and tiles read shares of the latest period. A missing, negative, or zero-total period becomes a gap across the whole stack, and hiding a series keeps the original denominator.
### Period select
```tsx
```
### Hover
Hovering a slot lifts its bars while the rest recede, the headline counts to that period’s total, and every tile shows its value there. Click to pin a period; arrow keys move it. Set `hover` to `tooltip` or `headline` for a different readout.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `data` (`Row[]`): One row per x position. Omit when using ranges.
- `x` (`key of Row`): Text, number, or Date field for the x axis.
- `series` (`{ key, label?, color?, dashed? }[]`): Numeric fields to plot, checked against your row type. Dashed series are references left out of the headline.
- `stack` (`boolean | 'percent'`): Stack the bars: `true` adds them, `percent` shows shares. Omit to group them side by side. Dashed series stay lines over the stack.
- `radius` (`number`): Corner radius in pixels. Defaults to 6.
- `corners` (`'end' | 'all'`): Round only the value end (default) or every corner, so stacked segments read as separate rounded blocks.
- `tracks` (`boolean`): Quiet full-height lanes behind each bar, or behind each stacked column.
- `barWidth` (`number`): Maximum bar width in pixels.
- `barStyle` (`'solid' | 'segmented' | 'needle' | 'gradient' | 'outline' | 'isometric'`): How bars are drawn. Needles expand on hover; segmented cells trim to the exact value. Isometric bars are square prisms with a lit top and shaded side; the front keeps the measured height and `radius` does not apply.
- `depth` (`boolean`): Shorthand for `barStyle="isometric"`: square blocks with a lit top and a shaded side. The front keeps the measured height.
- `aggregate` (`'sum' | 'mean' | 'last' | 'max'`): How the headline and tiles summarize the period. Defaults to sum.
- `bleed` (`boolean`): Bars stay inside the card padding by default so labels center on them.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `delta` (`number`): Fractional change for the chip: 0.082 shows +8.2%.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `headline` (`number`): Resting headline. Defaults to the aggregate of non-reference series; dashed series are excluded.
- `range` (`string`): Static period label in the header.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the data.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `tiles` (`boolean`): Per-series value tiles. Defaults to true; false hides the legend.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): False removes the legend without changing the data. How the legend under the plot lays out: value tiles (default), a compact inline key, list rows, tinted pills, or bars that also draw each value against the largest.
- `legendSwatch` (`'square' | 'dot' | 'line'`): The mark beside each legend label. Defaults to a rounded square.
- `height` (`number`): Plot height in pixels. Defaults to 240.
- `axis` (`'minimal' | 'dots' | 'inline' | 'ruler' | 'classic' | 'segmented' | { x, y }`): Axis preset. Minimal (default) labels only the x ends and has no grid. Set one per axis with `{ x, y }`; a segmented axis can take a `gradient` to read as a range.
- `hover` (`'pills' | 'tooltip' | 'strip' | 'headline'`): The one readout for the hovered point: pills on the axes (default), a tooltip with every series, a strip docked above the plot, or the headline and tiles alone.
- `hoverStyle` (`'soft' | 'solid' | 'accent'`): How the pills or tooltip look. Soft (default) is surface glass; accent tints it with the hovered series.
- `pillSeries` (`'nearest' | 'total' | key`): Which series the y pill reads and the tooltip leads with. Nearest (default) follows the pointer.
- `pillPosition` (`'auto' | 'mark' | 'axis'`): Where the value pill sits: above the hovered mark, or on the y axis. Auto picks mark when there are no y labels.
- `tooltipIndicator` (`'square' | 'dot' | 'line'`): Series marker on each tooltip row, with hover="tooltip". Square by default.
- `background` (`'dots' | 'grid' | 'lines' | 'none'`): Texture behind the marks. Dots by default, with a hover spotlight.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `axisInset` (`number`): Padding between the plot edges and axis labels or pills.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `compare` (`boolean | 'headline' | 'badge'`): Drag across the plot to compare two points in time. True or headline reads the change in the headline; badge reads it in the card’s tab and leaves the headline at rest.
- `target` (`number | { value, label? }`): A goal each point should reach: a labeled line, a “vs target” chip on hover, and a count of points on target at rest.
- `forecast` (`{ from, lower?, upper?, label?, bands?: { lower, upper, label }[] }`): Rows from `from` onward are projections: dotted and excluded from the headline. Supply lower/upper for one envelope, or bands ordered widest to narrowest for a fan on Line and unstacked Area. Every bound is inspectable; no forecast is estimated.
- `sync` (`string`): Link hover and pins with every card that uses the same name, matched by x value. A click pins them all, with a ghost pin on the others; Alt-click pins one card only.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `headlineSeries` (`key of Row`): Numeric series whose value drives the headline instead of the combined total.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `formatAxisValue` (`(value: number) => string`): Custom compact axis value text.
- `formatX` (`(value: string | number | Date) => string`): Custom x label text.
- `xType` (`'category' | 'number' | 'time'`): Override inferred x type. Use time for numeric Unix timestamps in milliseconds.
- `spotlight` (`boolean`): Highlight the inspected position in the plot background. Defaults to true.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
- `pillValue` (`'series' | 'stack'`): Read an individual series value (default) or its stacked height. Has no effect when the card has no stacked series.
- `decimate` (`boolean`): Defaults to true. Line and Area marks retain at most four observations per pixel column. Other marks draw every row; inspection and summaries always read the full data.
### Diverging responses: DivergingBarCard
Survey counts stack on either side of neutral. Neutral responses split around zero, and missing contributions leave the row incomplete rather than becoming zero. All three loading styles share the skeleton exit, entrance, pointer/keyboard pinning, touch glide, reduced motion, and accessible readings table. Aggregate marks report null as their original datum.
```tsx
import { DivergingBarCard } from '@lilt-ui/charts';
```
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 260. Dense lanes expand to keep every mark visible.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Legend layout; false hides it. Correlation defaults to false.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Legend marker, square by default.
- `category` (`text key of Row`): Unique response category.
- `series` (`{ key, label?, color?, side: 'negative' | 'neutral' | 'positive' }[]`): Nonnegative counts with an explicit side; at most one neutral series.
- `percent` (`boolean`): Normalize complete rows to 100%; readouts keep counts and percentages.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Horizontal bar: `HorizontalBarChartCard`
Rank categories and see what leads. Docs: https://liltui.vercel.app/charts/horizontal-bar
```tsx
import { HorizontalBarChartCard } from '@lilt-ui/charts';
```
### Complete examples
#### Horizontal bar card
```tsx
'use client';
import { HorizontalBarChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "month", "label": "This month", "data": [
{ "channel": "Organic search", "revenue": 42800 },
{ "channel": "Direct", "revenue": 24100 },
{ "channel": "Paid social", "revenue": 31500 },
{ "channel": "Email", "revenue": 18200 },
{ "channel": "Referral", "revenue": 12600 },
], "delta": 0.124 },
{ "id": "last-month", "label": "Last month", "data": [
{ "channel": "Organic search", "revenue": 36900 },
{ "channel": "Direct", "revenue": 25800 },
{ "channel": "Paid social", "revenue": 22400 },
{ "channel": "Email", "revenue": 19600 },
{ "channel": "Referral", "revenue": 9800 },
], "delta": 0.038 },
{ "id": "quarter", "label": "This quarter", "data": [
{ "channel": "Organic search", "revenue": 118400 },
{ "channel": "Email", "revenue": 86300 },
{ "channel": "Paid social", "revenue": 71900 },
{ "channel": "Direct", "revenue": 64200 },
{ "channel": "Partners", "revenue": 38700 },
], "delta": 0.217 },
];
export function Example() {
return (
);
}
```
#### Audience profile
Two audience profiles face one another around shared category labels. Both sides use one absolute scale; left-facing bars still represent positive counts.
```tsx
'use client';
import { MirroredBarCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const audienceAge = [
{ "age": "18–24", "current": 1240, "previous": 980 },
{ "age": "25–34", "current": 2860, "previous": 2480 },
{ "age": "35–44", "current": 2180, "previous": 2340 },
{ "age": "45–54", "current": 1560, "previous": 1820 },
{ "age": "55–64", "current": 980, "previous": 1240 },
{ "age": "65+", "current": 640, "previous": 820 },
];
export function Example() {
return (
);
}
```
#### Top five and the rest
`limit` keeps the list short. Everything past it is added up into one “Other” row, so the total stays true.
```tsx
'use client';
import { HorizontalBarChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This month", "data": [
{ "page": "/pricing", "views": 18420 },
{ "page": "/", "views": 42310 },
{ "page": "/docs/getting-started", "views": 15260 },
{ "page": "/blog/launch-week", "views": 9840 },
{ "page": "/changelog", "views": 7310 },
{ "page": "/docs/api", "views": 6120 },
{ "page": "/careers", "views": 3480 },
{ "page": "/about", "views": 2950 },
{ "page": "/legal/privacy", "views": 1210 },
] },
{ "id": "previous", "label": "Last month", "data": [
{ "page": "/pricing", "views": 15841 },
{ "page": "/", "views": 36387 },
{ "page": "/docs/getting-started", "views": 13124 },
{ "page": "/blog/launch-week", "views": 8462 },
{ "page": "/changelog", "views": 6287 },
{ "page": "/docs/api", "views": 5263 },
{ "page": "/careers", "views": 2993 },
{ "page": "/about", "views": 2537 },
{ "page": "/legal/privacy", "views": 1041 },
] },
];
export function Example() {
return (
);
}
```
#### Missing values
Brazil hasn’t reported yet. It says so, sorts last, and stays out of the total and every share.
```tsx
'use client';
import { HorizontalBarChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This month", "data": [
{ "country": "United States", "sales": 128400 },
{ "country": "Germany", "sales": 46200 },
{ "country": "United Kingdom", "sales": 51800 },
{ "country": "Japan", "sales": 33900 },
{ "country": "Brazil", "sales": null },
{ "country": "Canada", "sales": 27400 },
] },
{ "id": "previous", "label": "Last month", "data": [
{ "country": "United States", "sales": 110424 },
{ "country": "Germany", "sales": 39732 },
{ "country": "United Kingdom", "sales": 44548 },
{ "country": "Japan", "sales": 29154 },
{ "country": "Brazil", "sales": null },
{ "country": "Canada", "sales": 23564 },
] },
];
export function Example() {
return (
);
}
```
#### Gains and losses
Bars grow both ways from zero. Shares are hidden because a share of a mixed total means nothing.
```tsx
'use client';
import { HorizontalBarChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This month", "data": [
{ "product": "Analytics", "change": 18400 },
{ "product": "Billing", "change": 9200 },
{ "product": "Storage", "change": -4100 },
{ "product": "Messaging", "change": 5600 },
{ "product": "Legacy API", "change": -11800 },
] },
{ "id": "previous", "label": "Last month", "data": [
{ "product": "Analytics", "change": 15824 },
{ "product": "Billing", "change": 7912 },
{ "product": "Storage", "change": -3526 },
{ "product": "Messaging", "change": 4816 },
{ "product": "Legacy API", "change": -10148 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per category, in any order. Names must be unique.
const channelRevenue = [
{ channel: 'Organic search', revenue: 42800 },
{ channel: 'Direct', revenue: 24100 },
{ channel: 'Referral', revenue: null }, // still reporting
];
```
`category` names a text field and `value` a numeric one; TypeScript rejects anything else. The headline is the total, and each share is a row’s part of it. `null` rows say “No data”, sort last, and stay out of the total. When values go negative, shares are hidden, because a share of a total that mixes gains and losses means nothing.
### Period select
```tsx
```
### Hover
Hovering a row brightens its bar and dims the rest, and the headline counts to that row with its name and share beside it. Click to pin a row. Rows are buttons: Tab reaches the list, arrow keys move through it, Escape unpins. Switching the period re-ranks rows with a smooth slide.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per category. Omit when using ranges.
- `category` (`text key of Row`): Names each row. Must be unique.
- `value` (`numeric key of Row`): The amount to rank by.
- `sort` (`'descending' | 'ascending' | 'input'`): Largest first by default; input keeps your order.
- `limit` (`number`): Show the first rows and add the rest together as one “Other” row.
- `otherLabel` (`string`): Label of the combined row.
- `share` (`boolean`): Each row’s share of the total. Defaults to true.
- `rank` (`boolean`): Number each row by rank.
- `barStyle` (`'inline' | 'track' | 'lollipop' | 'isometric'`): Inline puts the label on a soft bar (default); track draws a slim bar below it; lollipop uses a stem and dot; isometric adds depth.
- `headline` (`number`): Resting headline. Defaults to the total of all rows.
- `delta` (`number`): Fractional change for the chip.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label in the header.
- `selected` (`string | null`): The pinned category, by name, when you own the selection, so outside filters and a click on the chart share it. `null` pins nothing; omit it and the card keeps its own pin.
- `onSelectedChange` (`(category: string | null) => void`): Asked when a click, tap, or Escape pins or releases a category.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the rows.
- `color` (`string`): Any CSS color for the bars.
- `depth` (`boolean`): Shorthand for `barStyle="isometric"`: a solid block under each label with a lit roof and a shaded end. The front ends at the value.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
### Mirrored bars: MirroredBarCard
Two audience profiles face one another around shared category labels. Both sides use one absolute scale; left-facing bars still represent positive counts. All three loading styles share the skeleton exit, entrance, pointer/keyboard pinning, touch glide, reduced motion, and accessible readings table. Aggregate marks report null as their original datum.
```tsx
import { MirroredBarCard } from '@lilt-ui/charts';
```
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 260. Dense lanes expand to keep every mark visible.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Legend layout; false hides it. Correlation defaults to false.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Legend marker, square by default.
- `category` (`text key of Row`): Unique label between the two sides.
- `left` (`numeric keys of Row`): Nonnegative measurements on one common scale.
- `right` (`numeric keys of Row`): Nonnegative measurements on one common scale.
- `leftLabel` (`string`): Names for the two cohorts.
- `rightLabel` (`string`): Names for the two cohorts.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Slope chart: `SlopeChartCard`
Compare two periods and see who rose and who fell. Docs: https://liltui.vercel.app/charts/slope
```tsx
import { SlopeChartCard } from '@lilt-ui/charts';
```
### Complete examples
#### Slope chart card
```tsx
'use client';
import { SlopeChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "year", "label": "2025 → 2026", "data": [
{ "region": "North America", "lastYear": 412000, "thisYear": 486000 },
{ "region": "Europe", "lastYear": 358000, "thisYear": 391000 },
{ "region": "Asia Pacific", "lastYear": 204000, "thisYear": 281000 },
{ "region": "Latin America", "lastYear": 118000, "thisYear": 104000 },
{ "region": "Middle East", "lastYear": 86000, "thisYear": 97000 },
{ "region": "Africa", "lastYear": 41000, "thisYear": 38000 },
] },
{ "id": "half", "label": "H1 → H2", "data": [
{ "region": "North America", "lastYear": 228000, "thisYear": 258000 },
{ "region": "Europe", "lastYear": 181000, "thisYear": 176000 },
{ "region": "Asia Pacific", "lastYear": 121000, "thisYear": 149000 },
{ "region": "Latin America", "lastYear": 57000, "thisYear": 52000 },
{ "region": "Middle East", "lastYear": 44000, "thisYear": 51000 },
{ "region": "Africa", "lastYear": 19000, "thisYear": 20000 },
] },
];
export function Example() {
return (
);
}
```
#### New and missing categories
A region that is new or still reporting keeps its known dot, says “No data” for the other, and stays out of the change.
```tsx
'use client';
import { SlopeChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This period", "data": [
{ "region": "North America", "lastYear": 412000, "thisYear": 486000 },
{ "region": "Europe", "lastYear": 358000, "thisYear": 391000 },
{ "region": "Asia Pacific", "lastYear": 204000, "thisYear": 281000 },
{ "region": "Nordics", "lastYear": null, "thisYear": 64000 },
{ "region": "Latin America", "lastYear": 118000, "thisYear": null },
] },
{ "id": "previous", "label": "Last period", "data": [
{ "region": "North America", "lastYear": 354320, "thisYear": 417960 },
{ "region": "Europe", "lastYear": 307880, "thisYear": 336260 },
{ "region": "Asia Pacific", "lastYear": 175440, "thisYear": 241660 },
{ "region": "Nordics", "lastYear": null, "thisYear": 55040 },
{ "region": "Latin America", "lastYear": 101480, "thisYear": null },
] },
];
export function Example() {
return (
);
}
```
#### When down is good
`deltaTone="inverse"` swaps the meaning of the colors for costs, churn, or response times.
```tsx
'use client';
import { SlopeChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This period", "data": [
{ "region": "North America", "lastYear": 412000, "thisYear": 486000 },
{ "region": "Europe", "lastYear": 358000, "thisYear": 391000 },
{ "region": "Asia Pacific", "lastYear": 204000, "thisYear": 281000 },
{ "region": "Latin America", "lastYear": 118000, "thisYear": 104000 },
{ "region": "Middle East", "lastYear": 86000, "thisYear": 97000 },
{ "region": "Africa", "lastYear": 41000, "thisYear": 38000 },
] },
{ "id": "previous", "label": "Last period", "data": [
{ "region": "North America", "lastYear": 354320, "thisYear": 417960 },
{ "region": "Europe", "lastYear": 307880, "thisYear": 336260 },
{ "region": "Asia Pacific", "lastYear": 175440, "thisYear": 241660 },
{ "region": "Latin America", "lastYear": 101480, "thisYear": 89440 },
{ "region": "Middle East", "lastYear": 73960, "thisYear": 83420 },
{ "region": "Africa", "lastYear": 35260, "thisYear": 32680 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per category, with a numeric field for each period.
const regionRevenue = [
{ region: 'North America', lastYear: 412000, thisYear: 486000 },
{ region: 'Nordics', lastYear: null, thisYear: 64000 }, // new this year
];
```
`category` names a text field; `from` and `to` name numeric fields, and TypeScript rejects anything else. The headline totals the later values (or averages them with `aggregate="mean"`). The change beside it compares only categories measured in both periods, so a new or late-reporting category never reads as growth or loss. Percentages appear only against a positive starting value.
### Period select
```tsx
```
### Hover
Hovering a line or row brightens it and dims the rest, and the headline counts to that category’s later value with its change beside it. Click to pin a category. Each one is a button: Tab reaches the chart, arrow keys move between categories, Escape unpins. Lines grow from their earlier value on first draw and re-tilt when the period changes.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per category with both values. Omit when using ranges.
- `category` (`text key of Row`): Names each row. Must be unique.
- `from` (`numeric key of Row`): The earlier value.
- `to` (`numeric key of Row`): The later value.
- `fromLabel` (`string`): Names the earlier period. Defaults to the key.
- `toLabel` (`string`): Names the later period. Defaults to the key.
- `variant` (`'slope' | 'dumbbell'`): Lines across two columns (default), or rows on one shared scale.
- `sort` (`'change' | 'to' | 'input'`): Largest gain first by default; `to` ranks by the later value.
- `aggregate` (`'sum' | 'mean'`): How the headline summarizes categories. Use mean for rates and shares.
- `headline` (`number`): Resting headline. Defaults to the later values, summarized.
- `delta` (`number`): Fractional change for the chip. Defaults to the change in total.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good; it also swaps the line colors.
- `range` (`string`): Static period label in the header.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the rows.
- `color` (`string`): One color for every category instead of rise and fall colors.
- `height` (`number`): Plot height of the slope variant in pixels. Defaults to 260.
- `depth` (`boolean`): Draws each change as a lit tube between two spheres. Dumbbells get the same look.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
## Range chart: `RangeChartCard`
A low and a high for every observation: floating bars, or error bars around a value. Docs: https://liltui.vercel.app/charts/range
```tsx
import { RangeChartCard } from '@lilt-ui/charts';
```
### Complete examples
#### Range card
```tsx
'use client';
import { RangeChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const cityTemperature = [
{ "month": "Jan", "low": 2, "high": 9, "mean": 5.5 },
{ "month": "Feb", "low": 3, "high": 11, "mean": 7 },
{ "month": "Mar", "low": 5, "high": 14, "mean": 9.5 },
{ "month": "Apr", "low": 7, "high": 17, "mean": 12 },
{ "month": "May", "low": 11, "high": 21, "mean": 16 },
{ "month": "Jun", "low": 14, "high": 25, "mean": 19.5 },
{ "month": "Jul", "low": 16, "high": 28, "mean": 22 },
{ "month": "Aug", "low": 16, "high": 27, "mean": 21.5 },
{ "month": "Sep", "low": 13, "high": 23, "mean": 18 },
{ "month": "Oct", "low": 9, "high": 18, "mean": 13.5 },
{ "month": "Nov", "low": 5, "high": 12, "mean": 8.5 },
{ "month": "Dec", "low": 3, "high": 9, "mean": 6 },
];
export function Example() {
return (
);
}
```
#### Timeline
Start and end times on service lanes. Overlaps stack into separate rows. Depth turns the same intervals into solid bars.
```tsx
'use client';
import { TimelineChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This period", "data": [
{ "id": "a", "task": "API release", "service": "API", "state": "Deploy", "start": "2026-09-28T08:00:00Z", "end": "2026-09-28T10:30:00Z" },
{ "id": "b", "task": "Index rebuild", "service": "API", "state": "Maintenance", "start": "2026-09-28T09:30:00Z", "end": "2026-09-28T12:00:00Z" },
{ "id": "c", "task": "Web release", "service": "Web", "state": "Deploy", "start": "2026-09-28T10:00:00Z", "end": "2026-09-28T13:00:00Z" },
{ "id": "d", "task": "Cache refresh", "service": "Workers", "state": "Maintenance", "start": "2026-09-28T08:30:00Z", "end": "2026-09-28T11:00:00Z" },
{ "id": "e", "task": "Queue drain", "service": "Workers", "state": "Recovery", "start": "2026-09-28T12:00:00Z", "end": "2026-09-28T15:00:00Z" },
] },
{ "id": "previous", "label": "Last period", "data": [
{ "id": "a", "task": "API release", "service": "API", "state": "Deploy", "start": "2026-09-28T08:00:00Z", "end": "2026-09-28T10:30:00Z" },
{ "id": "b", "task": "Index rebuild", "service": "API", "state": "Maintenance", "start": "2026-09-28T09:30:00Z", "end": "2026-09-28T12:00:00Z" },
{ "id": "c", "task": "Web release", "service": "Web", "state": "Deploy", "start": "2026-09-28T10:00:00Z", "end": "2026-09-28T13:00:00Z" },
{ "id": "d", "task": "Cache refresh", "service": "Workers", "state": "Maintenance", "start": "2026-09-28T08:30:00Z", "end": "2026-09-28T11:00:00Z" },
{ "id": "e", "task": "Queue drain", "service": "Workers", "state": "Recovery", "start": "2026-09-28T12:00:00Z", "end": "2026-09-28T15:00:00Z" },
] },
];
export function Example() {
return (
);
}
```
#### Error bars
Each variant’s conversion rate with its 95% confidence interval as whiskers.
```tsx
'use client';
import { RangeChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const experimentResults = [
{ "variant": "Control", "rate": 0.041, "low": 0.036, "high": 0.046 },
{ "variant": "Short form", "rate": 0.052, "low": 0.046, "high": 0.058 },
{ "variant": "Social proof", "rate": 0.047, "low": 0.041, "high": 0.053 },
{ "variant": "Annual default", "rate": 0.039, "low": 0.033, "high": 0.045 },
{ "variant": "Free trial", "rate": 0.061, "low": 0.054, "high": 0.068 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per x with the low and high of its range, and optionally a value inside it.
const temperature = [
{ month: 'Jan', low: 2, high: 9, mean: 5.5 },
{ month: 'Feb', low: 3, high: 11, mean: 7 },
];
```
Each range needs `low` at or below `high`; error bars also need the value between them. The headline averages the values by default (`aggregate="mean"`), because ranges rarely add up. Without `value`, the high of each range drives the headline and pills. The same marks are available as `RangeBar` and `ErrorBar` primitives, reading any series’ `fields`.
### Hover
Hover a range to read its low and high beside the value, and to lift it over the dimmed rest.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `data` (`Row[]`): One row per x position. Omit when using ranges.
- `x` (`key of Row`): Text, number, or Date field for the x axis.
- `low` (`key of Row`): Numeric field holding each range’s low.
- `high` (`key of Row`): Numeric field holding each range’s high.
- `value` (`key of Row`): Numeric field holding the measured value. Defaults to high.
- `label` (`string`): Names the series in hover.
- `color` (`string`): Any CSS color.
- `display` (`'bar' | 'error'`): Floating bars (default), or whiskers around a dot at the value.
- `depth` (`boolean`): Draws each bar as a solid block whose front spans exactly low to high. Error bars stay flat.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `delta` (`number`): Fractional change for the chip: 0.082 shows +8.2%.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `headline` (`number`): Resting headline. Defaults to the aggregate of non-reference series; dashed series are excluded.
- `range` (`string`): Static period label in the header.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the data.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): False removes the legend without changing the data. How the legend under the plot lays out: value tiles (default), a compact inline key, list rows, tinted pills, or bars that also draw each value against the largest.
- `legendSwatch` (`'square' | 'dot' | 'line'`): The mark beside each legend label. Defaults to a rounded square.
- `height` (`number`): Plot height in pixels. Defaults to 240.
- `axis` (`'minimal' | 'dots' | 'inline' | 'ruler' | 'classic' | 'segmented' | { x, y }`): Axis preset. Minimal (default) labels only the x ends and has no grid. Set one per axis with `{ x, y }`; a segmented axis can take a `gradient` to read as a range.
- `hover` (`'pills' | 'tooltip' | 'strip' | 'headline'`): The one readout for the hovered point: pills on the axes (default), a tooltip with every series, a strip docked above the plot, or the headline and tiles alone.
- `hoverStyle` (`'soft' | 'solid' | 'accent'`): How the pills or tooltip look. Soft (default) is surface glass; accent tints it with the hovered series.
- `pillPosition` (`'auto' | 'mark' | 'axis'`): Where the value pill sits: above the hovered mark, or on the y axis. Auto picks mark when there are no y labels.
- `tooltipIndicator` (`'square' | 'dot' | 'line'`): Series marker on each tooltip row, with hover="tooltip". Square by default.
- `background` (`'dots' | 'grid' | 'lines' | 'none'`): Texture behind the marks. Dots by default, with a hover spotlight.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `axisInset` (`number`): Padding between the plot edges and axis labels or pills.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `compare` (`boolean | 'headline' | 'badge'`): Drag across the plot to compare two points in time. True or headline reads the change in the headline; badge reads it in the card’s tab and leaves the headline at rest.
- `sync` (`string`): Link hover and pins with every card that uses the same name, matched by x value. A click pins them all, with a ghost pin on the others; Alt-click pins one card only.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `aggregate` (`'sum' | 'mean' | 'last' | 'max'`): Summary at rest: sum for counts, mean for rates, last for levels, or max for peaks. Area defaults to sum; Range defaults to mean.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `formatAxisValue` (`(value: number) => string`): Custom compact axis value text.
- `formatX` (`(value: string | number | Date) => string`): Custom x label text.
- `xType` (`'category' | 'number' | 'time'`): Override inferred x type. Use time for numeric Unix timestamps in milliseconds.
- `spotlight` (`boolean`): Highlight the inspected position in the plot background. Defaults to true.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
- `pillValue` (`'series' | 'stack'`): Read an individual series value (default) or its stacked height. Has no effect when the card has no stacked series.
- `decimate` (`boolean`): Defaults to true. Line and Area marks retain at most four observations per pixel column. Other marks draw every row; inspection and summaries always read the full data.
- `tiles` (`boolean`): Show the range series value tile beneath the plot. Defaults to false.
### Timeline intervals: TimelineChartCard
TimelineChartCard draws elapsed time horizontally. Dates, ISO strings, and epoch milliseconds are accepted. Missing endpoints stay unplotted and are counted; reversed intervals are rejected. Overlaps stack without hiding observations. Duration values and summaries are milliseconds, formatted as hours by default; simultaneous intervals add independently.
```tsx
import { TimelineChartCard } from '@lilt-ui/charts';
```
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 260. Dense lanes expand to keep every mark visible.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `label` (`text key of Row`): Names each interval; must be unique unless id is supplied.
- `id` (`text key of Row`): Stable unique interval identity.
- `start` (`date, string, or numeric key of Row`): UTC endpoints. Equal endpoints render a small instant marker.
- `end` (`date, string, or numeric key of Row`): UTC endpoints. Equal endpoints render a small instant marker.
- `lane` (`text key of Row`): Groups intervals into labeled lanes; overlaps get separate subrows.
- `group` (`text key of Row`): Colors intervals by a category and creates its duration legend.
- `formatTime` (`(timestamp: number) => string`): Formats axis ticks and endpoint readouts.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Duration legend layout; tiles by default.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Legend marker; square by default.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Radial chart: `RadialChartCard`
Show how each part contributes to the whole. Docs: https://liltui.vercel.app/charts/radial
```tsx
import { RadialChartCard } from '@lilt-ui/charts';
```
### Complete examples
#### Radial chart card
```tsx
'use client';
import { RadialChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "month", "label": "This month", "data": [
{ "channel": "Organic search", "revenue": 42800 },
{ "channel": "Direct", "revenue": 24100 },
{ "channel": "Paid social", "revenue": 31500 },
{ "channel": "Email", "revenue": 18200 },
{ "channel": "Referral", "revenue": 12600 },
], "delta": 0.124 },
{ "id": "last-month", "label": "Last month", "data": [
{ "channel": "Organic search", "revenue": 36900 },
{ "channel": "Direct", "revenue": 25800 },
{ "channel": "Paid social", "revenue": 22400 },
{ "channel": "Email", "revenue": 19600 },
{ "channel": "Referral", "revenue": 9800 },
], "delta": 0.038 },
{ "id": "quarter", "label": "This quarter", "data": [
{ "channel": "Organic search", "revenue": 118400 },
{ "channel": "Email", "revenue": 86300 },
{ "channel": "Paid social", "revenue": 71900 },
{ "channel": "Direct", "revenue": 64200 },
{ "channel": "Partners", "revenue": 38700 },
], "delta": 0.217 },
];
export function Example() {
return (
);
}
```
#### Spend hierarchy
Inner rings show departments; outer rings show their teams. Pinning retains a branch and its ancestors. Leaf-only paths prevent parent totals from being counted twice.
```tsx
'use client';
import { NestedDonutCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const expenseHierarchy = [
{ "path": "Product/Engineering", "spend": 48000 },
{ "path": "Product/Design", "spend": 23000 },
{ "path": "Growth/Acquisition", "spend": 32000 },
{ "path": "Growth/Content", "spend": 14000 },
{ "path": "Operations/Support", "spend": 21000 },
{ "path": "Operations/Infrastructure", "spend": 28000 },
];
export function Example() {
return (
);
}
```
#### Many categories
Nine sources, five slices: past the `limit` the rest add up to one gray “Other” slice, so colors stay distinct and the total stays true.
```tsx
'use client';
import { RadialChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This month", "data": [
{ "source": "Google", "sessions": 48200 },
{ "source": "Direct", "sessions": 31500 },
{ "source": "Newsletter", "sessions": 12800 },
{ "source": "LinkedIn", "sessions": 9400 },
{ "source": "Hacker News", "sessions": 7300 },
{ "source": "Bing", "sessions": 4100 },
{ "source": "Reddit", "sessions": 3600 },
{ "source": "DuckDuckGo", "sessions": 2200 },
{ "source": "GitHub", "sessions": 1900 },
] },
{ "id": "previous", "label": "Last month", "data": [
{ "source": "Google", "sessions": 41452 },
{ "source": "Direct", "sessions": 27090 },
{ "source": "Newsletter", "sessions": 11008 },
{ "source": "LinkedIn", "sessions": 8084 },
{ "source": "Hacker News", "sessions": 6278 },
{ "source": "Bing", "sessions": 3526 },
{ "source": "Reddit", "sessions": 3096 },
{ "source": "DuckDuckGo", "sessions": 1892 },
{ "source": "GitHub", "sessions": 1634 },
] },
];
export function Example() {
return (
);
}
```
#### Missing values
Design hasn’t reported yet. It stays in the legend as “No data” and takes no room in the circle, so the other shares are of what is known.
```tsx
'use client';
import { RadialChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "Q3", "data": [
{ "team": "Engineering", "spend": 184000 },
{ "team": "Marketing", "spend": 96000 },
{ "team": "Sales", "spend": 121000 },
{ "team": "Design", "spend": null },
{ "team": "Support", "spend": 42000 },
] },
{ "id": "previous", "label": "Q2", "data": [
{ "team": "Engineering", "spend": 158240 },
{ "team": "Marketing", "spend": 82560 },
{ "team": "Sales", "spend": 104060 },
{ "team": "Design", "spend": null },
{ "team": "Support", "spend": 36120 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per category, in any order. Names must be unique.
const channelRevenue = [
{ channel: 'Organic search', revenue: 42800 },
{ channel: 'Direct', revenue: 24100 },
{ channel: 'Referral', revenue: null }, // not reported: listed, not drawn
];
```
`category` names a text field and `value` a numeric one; TypeScript rejects anything else. The headline is the total and each share is a slice’s part of it. `null` rows stay in the legend as “No data” but take no room in the circle. A slice can’t be negative, so a negative value shows an error instead of a misleading chart.
### Period select
```tsx
```
### Hover
Hovering a slice or its legend row lifts that slice, dims the rest, and counts the headline to its value with its name and share beside it. The donut’s center shows the share. Click to pin; legend rows are buttons, so Tab and the arrow keys work too. Escape clears the pin in every legend layout. With legend={false}, Tab focuses the graphic; arrows inspect, Home/End jump, and Enter/Space pin or release. Switching the period eases every slice to its new size, and each category keeps its color.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per category. Omit when using ranges.
- `category` (`text key of Row`): Names each slice. Must be unique.
- `value` (`numeric key of Row`): Sizes each slice. Never negative; null is No data.
- `variant` (`'donut' | 'pie' | 'semi' | 'rings'`): Donut (default) shows the share in the middle, pie fills the circle, semi is a half donut, and rings give each category its own ring.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): False removes the legend without changing the data. Ranked rows with shares (list), value tiles, an inline key, tinted pills, or bars against the largest. Rings default to tiles, semi to inline.
- `legendSwatch` (`'square' | 'dot' | 'line'`): The mark beside each legend label. Defaults to a rounded square.
- `limit` (`number`): Slices before the rest become “Other”. Defaults to 5; Infinity shows all.
- `otherLabel` (`string`): Label of the combined slice.
- `sort` (`'descending' | 'ascending' | 'input'`): Largest first by default; input keeps your order.
- `headline` (`number`): Resting headline. Defaults to the total of all slices.
- `delta` (`number`): Fractional change for the chip.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label in the header.
- `selected` (`string | null`): The pinned category, by name, when you own the selection, so outside filters and a click on the chart share it. `null` pins nothing; omit it and the card keeps its own pin.
- `onSelectedChange` (`(category: string | null) => void`): Asked when a click, tap, or Escape pins or releases a category.
- `colors` (`Record`): Fixed colors by category name, e.g. `{ Critical: "#ef4444" }`. Others take the palette and keep it as values change.
- `center` (`({ category, value, share, active, pinned }) => ReactNode`): Replaces the middle of a donut or half donut, which by default shows the share of the hovered, pinned, or largest category.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the rows.
- `depth` (`boolean`): Lights every slice or ring as a tube, makes ring tracks grooves, and adds a soft shadow. Outlines keep their exact angles.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
### Nested donuts: NestedDonutCard
Inner rings show departments; outer rings show their teams. Pinning retains a branch and its ancestors. Leaf-only paths prevent parent totals from being counted twice. All three loading styles share the skeleton exit, entrance, pointer/keyboard pinning, touch glide, reduced motion, and accessible readings table. Aggregate marks report null as their original datum.
```tsx
import { NestedDonutCard } from '@lilt-ui/charts';
```
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 260. Dense lanes expand to keep every mark visible.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Legend layout; false hides it. Correlation defaults to false.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Legend marker, square by default.
- `path` (`text key of Row`): Unique leaf paths separated by /; up to eight levels.
- `value` (`numeric key of Row`): Nonnegative leaf area. Missing leaves contribute no known area.
- `hole` (`number`): Inner hole as a fraction of radius, default 0.3.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Treemap: `TreemapChartCard`
See how each part contributes to the whole, with related parts grouped together. Docs: https://liltui.vercel.app/charts/treemap
```tsx
import { TreemapChartCard } from '@lilt-ui/charts';
```
### Complete examples
#### Product revenue
```tsx
'use client';
import { TreemapChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const productRevenue = [
{ "product": "Analytics", "department": "Platform", "revenue": 42000 },
{ "product": "Automations", "department": "Platform", "revenue": 28000 },
{ "product": "Reports", "department": "Platform", "revenue": 16000 },
{ "product": "Team", "department": "Workspace", "revenue": 32000 },
{ "product": "Enterprise", "department": "Workspace", "revenue": 24000 },
{ "product": "Storage", "department": "Services", "revenue": 18000 },
{ "product": "Support", "department": "Services", "revenue": 12000 },
];
export function Example() {
return (
);
}
```
#### One level
Without a group, all products share one layout and each leaf gets its own palette color.
```tsx
'use client';
import { TreemapChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This period", "data": [
{ "product": "Analytics", "department": "Platform", "revenue": 42000 },
{ "product": "Automations", "department": "Platform", "revenue": 28000 },
{ "product": "Reports", "department": "Platform", "revenue": 16000 },
{ "product": "Team", "department": "Workspace", "revenue": 32000 },
{ "product": "Enterprise", "department": "Workspace", "revenue": 24000 },
{ "product": "Storage", "department": "Services", "revenue": 18000 },
{ "product": "Support", "department": "Services", "revenue": 12000 },
] },
{ "id": "previous", "label": "Last period", "data": [
{ "product": "Analytics", "department": "Platform", "revenue": 36120 },
{ "product": "Automations", "department": "Platform", "revenue": 24080 },
{ "product": "Reports", "department": "Platform", "revenue": 13760 },
{ "product": "Team", "department": "Workspace", "revenue": 27520 },
{ "product": "Enterprise", "department": "Workspace", "revenue": 20640 },
{ "product": "Storage", "department": "Services", "revenue": 15480 },
{ "product": "Support", "department": "Services", "revenue": 10320 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const productRevenue = [
{ product: 'Analytics', department: 'Platform', revenue: 42000 },
{ product: 'Automations', department: 'Platform', revenue: 28000 },
{ product: 'Team', department: 'Workspace', revenue: 32000 },
];
```
Each row is a leaf, with a nonnegative area. group optionally supplies one parent level; do not include parent totals as additional rows. Labels must be unique within their group. Null is missing and zero has no area: both remain in the accessible table. Negative areas and duplicate identities produce an error. Small tiles keep their full accessible name even when the visible label does not fit.
### Hover
Hover or focus a tile to read its value in the headline. Click or press Enter to pin; Escape releases. Arrow keys step through tiles, and Home/End jump to either end. The group legend highlights matching tiles. Use renderReadout and onSelectionChange for your own JSX. Skeletons use the same shimmer, draw, breathe, and opacity exit as the other cards; reduced motion skips decorative transitions.
### Props
- `drilldown` (`boolean`): Show explicit group buttons and a breadcrumb. Exploring a group animates leaves into their new layout; clicking a leaf still pins it.
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 260. Dense lanes expand to keep every mark visible.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `label` (`text key of Row`): Unique leaf name within its group.
- `value` (`numeric key of Row`): Nonnegative tile area.
- `group` (`text key of Row`): Optional parent category, shared color, and value legend.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Group legend layout. Defaults to tiles; false removes it.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Legend marker; square by default.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Funnel chart: `FunnelChartCard`
Follow conversion from the first step to the last. Docs: https://liltui.vercel.app/charts/funnel
```tsx
import { FunnelChartCard } from '@lilt-ui/charts';
```
### Complete examples
#### Funnel chart card
```tsx
'use client';
import { FunnelChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "week", "label": "Last 7 days", "data": [
{ "stage": "Link opened", "people": 197 },
{ "stage": "Started", "people": 110 },
{ "stage": "Completed", "people": 77 },
{ "stage": "Converted", "people": 38 },
], "delta": 0.052 },
{ "id": "month", "label": "Last 30 days", "data": [
{ "stage": "Link opened", "people": 860 },
{ "stage": "Started", "people": 470 },
{ "stage": "Completed", "people": 330 },
{ "stage": "Converted", "people": 160 },
], "delta": 0.031 },
];
export function Example() {
return (
);
}
```
#### Onboarding experiment
Two cohorts pass through the same stages on one absolute scale. Every stage reports its count and conversion from its own entry cohort.
```tsx
'use client';
import { ComparativeFunnelCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const cohortConversion = [
{ "stage": "Visit", "experiment": 12000, "control": 11800 },
{ "stage": "Explore", "experiment": 8400, "control": 7900 },
{ "stage": "Trial", "experiment": 4800, "control": 3900 },
{ "stage": "Activate", "experiment": 3200, "control": 2400 },
{ "stage": "Subscribe", "experiment": 2100, "control": 1450 },
];
export function Example() {
return (
);
}
```
#### Checkout drop-off
`colors="single"` keeps attention on the shape of the drop rather than on the stages.
```tsx
'use client';
import { FunnelChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "Last 7 days", "data": [
{ "stage": "Viewed", "people": 41800 },
{ "stage": "Basket", "people": 18400 },
{ "stage": "Checkout", "people": 9400 },
{ "stage": "Payment", "people": 6200 },
{ "stage": "Paid", "people": 5200 },
], "delta": -0.018 },
{ "id": "previous", "label": "Previous 7 days", "data": [
{ "stage": "Viewed", "people": 35948 },
{ "stage": "Basket", "people": 15824 },
{ "stage": "Checkout", "people": 8084 },
{ "stage": "Payment", "people": 5332 },
{ "stage": "Paid", "people": 4472 },
], "delta": -0.008 },
];
export function Example() {
return (
);
}
```
#### A hiring pipeline
Full-height lanes mark where 100% sits, so even the smallest stages have a frame.
```tsx
'use client';
import { FunnelChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "Last 7 days", "data": [
{ "stage": "Applied", "people": 1240 },
{ "stage": "Screened", "people": 420 },
{ "stage": "Phone", "people": 96 },
{ "stage": "Offer", "people": 18 },
{ "stage": "Hired", "people": 11 },
] },
{ "id": "previous", "label": "Previous 7 days", "data": [
{ "stage": "Applied", "people": 1066 },
{ "stage": "Screened", "people": 361 },
{ "stage": "Phone", "people": 83 },
{ "stage": "Offer", "people": 15 },
{ "stage": "Hired", "people": 9 },
] },
];
export function Example() {
return (
);
}
```
#### A stage with no data
Team invites aren’t tracked yet. That stage says “No data” and draws no band, and the stages around it keep their true shares of the first.
```tsx
'use client';
import { FunnelChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "Last 7 days", "data": [
{ "stage": "Signed up", "people": 5200 },
{ "stage": "Verified email", "people": 4100 },
{ "stage": "Invited team", "people": null },
{ "stage": "Created project", "people": 1900 },
] },
{ "id": "previous", "label": "Previous 7 days", "data": [
{ "stage": "Signed up", "people": 4472 },
{ "stage": "Verified email", "people": 3526 },
{ "stage": "Invited team", "people": null },
{ "stage": "Created project", "people": 1634 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per stage, in funnel order. Counts only stay level or fall.
const signupFunnel = [
{ stage: 'Link opened', people: 197 },
{ stage: 'Started', people: 110 },
{ stage: 'Completed', people: 77 },
{ stage: 'Converted', people: 38 },
];
```
Rows are stages in order: `category` names each one and `value` counts who reached it; TypeScript rejects anything else. Every percentage is a share of the first stage, and the headline is the first stage’s count. A stage that is `null` says “No data” and draws no band. A later stage with more people than an earlier one shows an error, because a funnel can only narrow.
### Period select
```tsx
```
### Hover
Hovering a stage, or its tile, dims the others and counts the headline to that stage, with the conversion from the step before beside it: “Started · 56% of Link opened”. Click to pin a stage. Bands sweep in from the left on first view and ease to their new size when the period changes.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per stage, in order. Omit when using ranges.
- `category` (`text key of Row`): Names each stage. Must be unique.
- `value` (`numeric key of Row`): How many reached the stage. Never rises from one stage to the next.
- `curve` (`'smooth' | 'linear'`): Smooth (default) eases each stage into the next; linear tapers straight.
- `colors` (`'stages' | 'single'`): A palette color per stage (default), or one color for every stage.
- `tracks` (`boolean`): A quiet full-height lane behind each stage, marking where 100% sits.
- `height` (`number`): Plot height in pixels. Defaults to 180.
- `headline` (`number`): Resting headline. Defaults to the first stage.
- `delta` (`number`): Fractional change for the chip.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label in the header.
- `selected` (`string | null`): The pinned stage, by name, when you own the selection, so outside filters and a click on the chart share it. `null` pins nothing; omit it and the card keeps its own pin.
- `onSelectedChange` (`(stage: string | null) => void`): Asked when a click, tap, or Escape pins or releases a stage.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the stages.
- `color` (`string`): Any CSS color for `colors="single"`.
- `depth` (`boolean`): Draws the funnel as a pipe: each stage shaded as a cylinder of its own thickness, with curved seams and rounded ends.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): False removes the legend without changing the data. How the stage legend lays out: value tiles (default), a compact inline key, list rows, tinted pills, or bars against the largest.
- `legendSwatch` (`'square' | 'dot' | 'line'`): The mark beside each legend label. Defaults to a rounded square.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
### Comparative funnel: ComparativeFunnelCard
Two cohorts pass through the same stages on one absolute scale. Every stage reports its count and conversion from its own entry cohort. All three loading styles share the skeleton exit, entrance, pointer/keyboard pinning, touch glide, reduced motion, and accessible readings table. Aggregate marks report null as their original datum.
```tsx
import { ComparativeFunnelCard } from '@lilt-ui/charts';
```
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 260. Dense lanes expand to keep every mark visible.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Legend layout; false hides it. Correlation defaults to false.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Legend marker, square by default.
- `stage` (`text key of Row`): Unique stages in input order.
- `cohorts` (`readonly [CardSeries, CardSeries]`): Two distinct nonnegative, nonincreasing series. Missing stages remain unknown.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Sankey chart: `SankeyChartCard`
Trace how values flow from one stage to the next. Docs: https://liltui.vercel.app/charts/sankey
```tsx
import { SankeyChartCard } from '@lilt-ui/charts';
```
### Complete examples
#### Sankey chart card
```tsx
'use client';
import { SankeyChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "week", "label": "This week", "data": [
{ "from": "Search", "to": "Pricing", "visitors": 2400 },
{ "from": "Search", "to": "Product tour", "visitors": 1800 },
{ "from": "Social", "to": "Product tour", "visitors": 1500 },
{ "from": "Social", "to": "Pricing", "visitors": 500 },
{ "from": "Email", "to": "Pricing", "visitors": 900 },
{ "from": "Email", "to": "Product tour", "visitors": 300 },
{ "from": "Pricing", "to": "Signed up", "visitors": 1300 },
{ "from": "Pricing", "to": "Left", "visitors": 2500 },
{ "from": "Product tour", "to": "Signed up", "visitors": 900 },
{ "from": "Product tour", "to": "Left", "visitors": 2700 },
], "delta": 0.163 },
{ "id": "last-week", "label": "Last week", "data": [
{ "from": "Search", "to": "Pricing", "visitors": 2064 },
{ "from": "Search", "to": "Product tour", "visitors": 1548 },
{ "from": "Social", "to": "Product tour", "visitors": 1290 },
{ "from": "Social", "to": "Pricing", "visitors": 430 },
{ "from": "Email", "to": "Pricing", "visitors": 774 },
{ "from": "Email", "to": "Product tour", "visitors": 258 },
{ "from": "Pricing", "to": "Signed up", "visitors": 1040 },
{ "from": "Pricing", "to": "Left", "visitors": 2000 },
{ "from": "Product tour", "to": "Signed up", "visitors": 720 },
{ "from": "Product tour", "to": "Left", "visitors": 2160 },
], "delta": 0.042 },
];
export function Example() {
return (
);
}
```
#### Drop-off between steps
Each checkout step passes on fewer people than it receives. Hover Shipping to read how many left there, even though no flow records where they went.
```tsx
'use client';
import { SankeyChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This week", "data": [
{ "from": "Cart", "to": "Shipping", "visitors": 1000 },
{ "from": "Shipping", "to": "Payment", "visitors": 640 },
{ "from": "Payment", "to": "Paid", "visitors": 410 },
] },
{ "id": "previous", "label": "Last week", "data": [
{ "from": "Cart", "to": "Shipping", "visitors": 860 },
{ "from": "Shipping", "to": "Payment", "visitors": 550 },
{ "from": "Payment", "to": "Paid", "visitors": 353 },
] },
];
export function Example() {
return (
);
}
```
#### Balanced flows
A budget has to add up, so `conservation="strict"` shows an error if Salaries passes on more or less than it receives. `valueFormat` makes every amount read as currency.
```tsx
'use client';
import { SankeyChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This week", "data": [
{ "from": "Revenue", "to": "Salaries", "amount": 520000 },
{ "from": "Revenue", "to": "Infrastructure", "amount": 180000 },
{ "from": "Revenue", "to": "Marketing", "amount": 140000 },
{ "from": "Revenue", "to": "Profit", "amount": 360000 },
{ "from": "Salaries", "to": "Engineering", "amount": 310000 },
{ "from": "Salaries", "to": "Sales", "amount": 120000 },
{ "from": "Salaries", "to": "Support", "amount": 90000 },
] },
{ "id": "previous", "label": "Last week", "data": [
{ "from": "Revenue", "to": "Salaries", "amount": 447200 },
{ "from": "Revenue", "to": "Infrastructure", "amount": 154800 },
{ "from": "Revenue", "to": "Marketing", "amount": 120400 },
{ "from": "Revenue", "to": "Profit", "amount": 309600 },
{ "from": "Salaries", "to": "Engineering", "amount": 266600 },
{ "from": "Salaries", "to": "Sales", "amount": 103200 },
{ "from": "Salaries", "to": "Support", "amount": 77400 },
] },
];
export function Example() {
return (
);
}
```
#### A flow that isn’t measured
Email → Product tour wasn’t instrumented yet. It isn’t drawn, the footer says so, and Email’s total counts only what was measured.
```tsx
'use client';
import { SankeyChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This week", "data": [
{ "from": "Search", "to": "Pricing", "visitors": 2400 },
{ "from": "Search", "to": "Product tour", "visitors": 1800 },
{ "from": "Social", "to": "Product tour", "visitors": 1500 },
{ "from": "Social", "to": "Pricing", "visitors": 500 },
{ "from": "Email", "to": "Pricing", "visitors": 900 },
{ "from": "Email", "to": "Product tour", "visitors": null },
{ "from": "Pricing", "to": "Signed up", "visitors": 1300 },
{ "from": "Pricing", "to": "Left", "visitors": 2500 },
{ "from": "Product tour", "to": "Signed up", "visitors": 900 },
{ "from": "Product tour", "to": "Left", "visitors": 2700 },
] },
{ "id": "previous", "label": "Last week", "data": [
{ "from": "Search", "to": "Pricing", "visitors": 2064 },
{ "from": "Search", "to": "Product tour", "visitors": 1548 },
{ "from": "Social", "to": "Product tour", "visitors": 1290 },
{ "from": "Social", "to": "Pricing", "visitors": 430 },
{ "from": "Email", "to": "Pricing", "visitors": 774 },
{ "from": "Email", "to": "Product tour", "visitors": null },
{ "from": "Pricing", "to": "Signed up", "visitors": 1118 },
{ "from": "Pricing", "to": "Left", "visitors": 2150 },
{ "from": "Product tour", "to": "Signed up", "visitors": 774 },
{ "from": "Product tour", "to": "Left", "visitors": 2322 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per flow, from one step to the next.
const visitorFlow = [
{ from: 'Search', to: 'Pricing', visitors: 2400 },
{ from: 'Pricing', to: 'Signed up', visitors: 1300 },
{ from: 'Email', to: 'Product tour', visitors: null }, // not measured
// …
];
```
Each row is one flow: `source` and `target` name the steps, and `value` says how much moved; TypeScript rejects anything else. Steps come from the names themselves and fall into columns by how many steps lead to them. Flows must move forward, so a loop shows an error. A step may pass on less than it receives, as when visitors leave without a tracked exit; `conservation="strict"` requires every middle step to balance. A flow that is `null` isn’t drawn, the footer says so, and totals count measured flows only.
### Period select
```tsx
```
### Hover
Hovering a ribbon reads that flow in the headline with its share of the step it left: “Pricing → Signed up · 34% of Pricing”. Hovering a step reads its total, its share of all traffic, and how many left there without a tracked flow. Everything unconnected dims. Click to pin. The diagram is one tab stop: arrow keys step through flows from left to right, Enter pins, and Escape lets go. Flows sweep in from the left on first view and when the period changes.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per flow. Omit when using ranges.
- `source` (`text key of Row`): Names the step a flow leaves.
- `target` (`text key of Row`): Names the step a flow reaches.
- `value` (`numeric key of Row`): How much moved. `null` means not measured: not drawn, and not counted.
- `conservation` (`'loss' | 'strict'`): Loss (default) lets a step pass on less than it receives; strict requires every middle step to balance.
- `height` (`number`): Plot height in pixels. Defaults to 280.
- `headline` (`number`): Resting headline. Defaults to everything entering the first steps.
- `delta` (`number`): Fractional change for the chip.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label in the header.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the flows.
- `depth` (`boolean`): Draws flows as lit pipes of their exact width and nodes as small blocks.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
## Stat cards: `StatCard`
Key metrics at a glance: a value, its change, and a small chart. Docs: https://liltui.vercel.app/charts/stat-cards
```tsx
import { StatCard } from '@lilt-ui/charts';
```
### Complete examples
#### Revenue
The default: the period total over a soft area.
```tsx
'use client';
import { StatCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const dailyKpis = [
{ "date": new Date('2026-09-01T00:00:00.000Z'), "revenue": 3120, "activeUsers": 1840, "orders": 96, "conversion": 0.031 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "revenue": 3380, "activeUsers": 1910, "orders": 104, "conversion": 0.033 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "revenue": 2940, "activeUsers": 1870, "orders": 88, "conversion": 0.029 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "revenue": 3510, "activeUsers": 1960, "orders": 110, "conversion": 0.034 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "revenue": 3720, "activeUsers": 2010, "orders": 118, "conversion": 0.035 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "revenue": 3290, "activeUsers": 1990, "orders": 101, "conversion": 0.032 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "revenue": 2860, "activeUsers": 1930, "orders": 84, "conversion": 0.028 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "revenue": 3640, "activeUsers": 2080, "orders": 112, "conversion": 0.033 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "revenue": 3910, "activeUsers": 2140, "orders": 121, "conversion": 0.036 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "revenue": 4080, "activeUsers": 2170, "orders": 126, "conversion": 0.035 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "revenue": 3760, "activeUsers": 2150, "orders": 115, "conversion": 0.033 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "revenue": 3450, "activeUsers": 2120, "orders": 103, "conversion": 0.031 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "revenue": 4210, "activeUsers": 2230, "orders": 131, "conversion": 0.036 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "revenue": 4390, "activeUsers": 2290, "orders": 137, "conversion": 0.037 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "revenue": 4020, "activeUsers": 2270, "orders": 124, "conversion": 0.034 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "revenue": 3680, "activeUsers": 2240, "orders": 112, "conversion": 0.032 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "revenue": 4460, "activeUsers": 2330, "orders": 139, "conversion": 0.036 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "revenue": 4620, "activeUsers": 2390, "orders": 145, "conversion": 0.037 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "revenue": 4280, "activeUsers": 2360, "orders": 132, "conversion": 0.035 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "revenue": 3940, "activeUsers": 2340, "orders": 119, "conversion": 0.033 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "revenue": 4710, "activeUsers": 2420, "orders": 148, "conversion": 0.038 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "revenue": 4930, "activeUsers": 2480, "orders": 155, "conversion": 0.038 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "revenue": 4560, "activeUsers": 2460, "orders": 141, "conversion": 0.036 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "revenue": 4180, "activeUsers": 2430, "orders": 128, "conversion": 0.034 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "revenue": 5020, "activeUsers": 2510, "orders": 158, "conversion": 0.038 },
{ "date": new Date('2026-09-26T00:00:00.000Z'), "revenue": 5240, "activeUsers": 2570, "orders": 166, "conversion": 0.039 },
{ "date": new Date('2026-09-27T00:00:00.000Z'), "revenue": 4870, "activeUsers": 2550, "orders": 151, "conversion": 0.037 },
{ "date": new Date('2026-09-28T00:00:00.000Z'), "revenue": 4490, "activeUsers": 2520, "orders": 138, "conversion": 0.035 },
{ "date": new Date('2026-09-29T00:00:00.000Z'), "revenue": 5310, "activeUsers": 2610, "orders": 169, "conversion": 0.039 },
{ "date": new Date('2026-09-30T00:00:00.000Z'), "revenue": 5560, "activeUsers": 2680, "orders": 177, "conversion": 0.04 },
];
export function Example() {
return (
);
}
```
#### Dashboard row
Four tiles over the same rows. Each picks its own field, summary, and chart, and the grid is yours. A shared `sync` name makes the three charts hover together.
```tsx
'use client';
import { StatCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const dailyKpis = [
{ "date": new Date('2026-09-01T00:00:00.000Z'), "revenue": 3120, "activeUsers": 1840, "orders": 96, "conversion": 0.031 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "revenue": 3380, "activeUsers": 1910, "orders": 104, "conversion": 0.033 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "revenue": 2940, "activeUsers": 1870, "orders": 88, "conversion": 0.029 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "revenue": 3510, "activeUsers": 1960, "orders": 110, "conversion": 0.034 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "revenue": 3720, "activeUsers": 2010, "orders": 118, "conversion": 0.035 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "revenue": 3290, "activeUsers": 1990, "orders": 101, "conversion": 0.032 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "revenue": 2860, "activeUsers": 1930, "orders": 84, "conversion": 0.028 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "revenue": 3640, "activeUsers": 2080, "orders": 112, "conversion": 0.033 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "revenue": 3910, "activeUsers": 2140, "orders": 121, "conversion": 0.036 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "revenue": 4080, "activeUsers": 2170, "orders": 126, "conversion": 0.035 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "revenue": 3760, "activeUsers": 2150, "orders": 115, "conversion": 0.033 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "revenue": 3450, "activeUsers": 2120, "orders": 103, "conversion": 0.031 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "revenue": 4210, "activeUsers": 2230, "orders": 131, "conversion": 0.036 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "revenue": 4390, "activeUsers": 2290, "orders": 137, "conversion": 0.037 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "revenue": 4020, "activeUsers": 2270, "orders": 124, "conversion": 0.034 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "revenue": 3680, "activeUsers": 2240, "orders": 112, "conversion": 0.032 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "revenue": 4460, "activeUsers": 2330, "orders": 139, "conversion": 0.036 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "revenue": 4620, "activeUsers": 2390, "orders": 145, "conversion": 0.037 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "revenue": 4280, "activeUsers": 2360, "orders": 132, "conversion": 0.035 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "revenue": 3940, "activeUsers": 2340, "orders": 119, "conversion": 0.033 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "revenue": 4710, "activeUsers": 2420, "orders": 148, "conversion": 0.038 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "revenue": 4930, "activeUsers": 2480, "orders": 155, "conversion": 0.038 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "revenue": 4560, "activeUsers": 2460, "orders": 141, "conversion": 0.036 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "revenue": 4180, "activeUsers": 2430, "orders": 128, "conversion": 0.034 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "revenue": 5020, "activeUsers": 2510, "orders": 158, "conversion": 0.038 },
{ "date": new Date('2026-09-26T00:00:00.000Z'), "revenue": 5240, "activeUsers": 2570, "orders": 166, "conversion": 0.039 },
{ "date": new Date('2026-09-27T00:00:00.000Z'), "revenue": 4870, "activeUsers": 2550, "orders": 151, "conversion": 0.037 },
{ "date": new Date('2026-09-28T00:00:00.000Z'), "revenue": 4490, "activeUsers": 2520, "orders": 138, "conversion": 0.035 },
{ "date": new Date('2026-09-29T00:00:00.000Z'), "revenue": 5310, "activeUsers": 2610, "orders": 169, "conversion": 0.039 },
{ "date": new Date('2026-09-30T00:00:00.000Z'), "revenue": 5560, "activeUsers": 2680, "orders": 177, "conversion": 0.04 },
];
export function Example() {
return (
);
}
```
#### Latest level
For a level such as active users, `aggregate="last"` shows the latest reading rather than a total.
```tsx
'use client';
import { StatCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const dailyKpis = [
{ "date": new Date('2026-09-01T00:00:00.000Z'), "revenue": 3120, "activeUsers": 1840, "orders": 96, "conversion": 0.031 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "revenue": 3380, "activeUsers": 1910, "orders": 104, "conversion": 0.033 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "revenue": 2940, "activeUsers": 1870, "orders": 88, "conversion": 0.029 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "revenue": 3510, "activeUsers": 1960, "orders": 110, "conversion": 0.034 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "revenue": 3720, "activeUsers": 2010, "orders": 118, "conversion": 0.035 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "revenue": 3290, "activeUsers": 1990, "orders": 101, "conversion": 0.032 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "revenue": 2860, "activeUsers": 1930, "orders": 84, "conversion": 0.028 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "revenue": 3640, "activeUsers": 2080, "orders": 112, "conversion": 0.033 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "revenue": 3910, "activeUsers": 2140, "orders": 121, "conversion": 0.036 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "revenue": 4080, "activeUsers": 2170, "orders": 126, "conversion": 0.035 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "revenue": 3760, "activeUsers": 2150, "orders": 115, "conversion": 0.033 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "revenue": 3450, "activeUsers": 2120, "orders": 103, "conversion": 0.031 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "revenue": 4210, "activeUsers": 2230, "orders": 131, "conversion": 0.036 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "revenue": 4390, "activeUsers": 2290, "orders": 137, "conversion": 0.037 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "revenue": 4020, "activeUsers": 2270, "orders": 124, "conversion": 0.034 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "revenue": 3680, "activeUsers": 2240, "orders": 112, "conversion": 0.032 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "revenue": 4460, "activeUsers": 2330, "orders": 139, "conversion": 0.036 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "revenue": 4620, "activeUsers": 2390, "orders": 145, "conversion": 0.037 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "revenue": 4280, "activeUsers": 2360, "orders": 132, "conversion": 0.035 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "revenue": 3940, "activeUsers": 2340, "orders": 119, "conversion": 0.033 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "revenue": 4710, "activeUsers": 2420, "orders": 148, "conversion": 0.038 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "revenue": 4930, "activeUsers": 2480, "orders": 155, "conversion": 0.038 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "revenue": 4560, "activeUsers": 2460, "orders": 141, "conversion": 0.036 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "revenue": 4180, "activeUsers": 2430, "orders": 128, "conversion": 0.034 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "revenue": 5020, "activeUsers": 2510, "orders": 158, "conversion": 0.038 },
{ "date": new Date('2026-09-26T00:00:00.000Z'), "revenue": 5240, "activeUsers": 2570, "orders": 166, "conversion": 0.039 },
{ "date": new Date('2026-09-27T00:00:00.000Z'), "revenue": 4870, "activeUsers": 2550, "orders": 151, "conversion": 0.037 },
{ "date": new Date('2026-09-28T00:00:00.000Z'), "revenue": 4490, "activeUsers": 2520, "orders": 138, "conversion": 0.035 },
{ "date": new Date('2026-09-29T00:00:00.000Z'), "revenue": 5310, "activeUsers": 2610, "orders": 169, "conversion": 0.039 },
{ "date": new Date('2026-09-30T00:00:00.000Z'), "revenue": 5560, "activeUsers": 2680, "orders": 177, "conversion": 0.04 },
];
export function Example() {
return (
);
}
```
#### Progress to a target
A row of cells fills toward `target`. The last cell is trimmed to the exact value, so 82% never rounds to a whole cell.
```tsx
'use client';
import { StatCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const dailyKpis = [
{ "date": new Date('2026-09-01T00:00:00.000Z'), "revenue": 3120, "activeUsers": 1840, "orders": 96, "conversion": 0.031 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "revenue": 3380, "activeUsers": 1910, "orders": 104, "conversion": 0.033 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "revenue": 2940, "activeUsers": 1870, "orders": 88, "conversion": 0.029 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "revenue": 3510, "activeUsers": 1960, "orders": 110, "conversion": 0.034 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "revenue": 3720, "activeUsers": 2010, "orders": 118, "conversion": 0.035 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "revenue": 3290, "activeUsers": 1990, "orders": 101, "conversion": 0.032 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "revenue": 2860, "activeUsers": 1930, "orders": 84, "conversion": 0.028 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "revenue": 3640, "activeUsers": 2080, "orders": 112, "conversion": 0.033 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "revenue": 3910, "activeUsers": 2140, "orders": 121, "conversion": 0.036 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "revenue": 4080, "activeUsers": 2170, "orders": 126, "conversion": 0.035 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "revenue": 3760, "activeUsers": 2150, "orders": 115, "conversion": 0.033 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "revenue": 3450, "activeUsers": 2120, "orders": 103, "conversion": 0.031 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "revenue": 4210, "activeUsers": 2230, "orders": 131, "conversion": 0.036 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "revenue": 4390, "activeUsers": 2290, "orders": 137, "conversion": 0.037 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "revenue": 4020, "activeUsers": 2270, "orders": 124, "conversion": 0.034 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "revenue": 3680, "activeUsers": 2240, "orders": 112, "conversion": 0.032 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "revenue": 4460, "activeUsers": 2330, "orders": 139, "conversion": 0.036 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "revenue": 4620, "activeUsers": 2390, "orders": 145, "conversion": 0.037 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "revenue": 4280, "activeUsers": 2360, "orders": 132, "conversion": 0.035 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "revenue": 3940, "activeUsers": 2340, "orders": 119, "conversion": 0.033 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "revenue": 4710, "activeUsers": 2420, "orders": 148, "conversion": 0.038 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "revenue": 4930, "activeUsers": 2480, "orders": 155, "conversion": 0.038 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "revenue": 4560, "activeUsers": 2460, "orders": 141, "conversion": 0.036 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "revenue": 4180, "activeUsers": 2430, "orders": 128, "conversion": 0.034 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "revenue": 5020, "activeUsers": 2510, "orders": 158, "conversion": 0.038 },
{ "date": new Date('2026-09-26T00:00:00.000Z'), "revenue": 5240, "activeUsers": 2570, "orders": 166, "conversion": 0.039 },
{ "date": new Date('2026-09-27T00:00:00.000Z'), "revenue": 4870, "activeUsers": 2550, "orders": 151, "conversion": 0.037 },
{ "date": new Date('2026-09-28T00:00:00.000Z'), "revenue": 4490, "activeUsers": 2520, "orders": 138, "conversion": 0.035 },
{ "date": new Date('2026-09-29T00:00:00.000Z'), "revenue": 5310, "activeUsers": 2610, "orders": 169, "conversion": 0.039 },
{ "date": new Date('2026-09-30T00:00:00.000Z'), "revenue": 5560, "activeUsers": 2680, "orders": 177, "conversion": 0.04 },
];
export function Example() {
return (
);
}
```
#### Ring past its target
Orders beat a 3,000 goal: a full ring and 128% inside it.
```tsx
'use client';
import { StatCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const dailyKpis = [
{ "date": new Date('2026-09-01T00:00:00.000Z'), "revenue": 3120, "activeUsers": 1840, "orders": 96, "conversion": 0.031 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "revenue": 3380, "activeUsers": 1910, "orders": 104, "conversion": 0.033 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "revenue": 2940, "activeUsers": 1870, "orders": 88, "conversion": 0.029 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "revenue": 3510, "activeUsers": 1960, "orders": 110, "conversion": 0.034 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "revenue": 3720, "activeUsers": 2010, "orders": 118, "conversion": 0.035 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "revenue": 3290, "activeUsers": 1990, "orders": 101, "conversion": 0.032 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "revenue": 2860, "activeUsers": 1930, "orders": 84, "conversion": 0.028 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "revenue": 3640, "activeUsers": 2080, "orders": 112, "conversion": 0.033 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "revenue": 3910, "activeUsers": 2140, "orders": 121, "conversion": 0.036 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "revenue": 4080, "activeUsers": 2170, "orders": 126, "conversion": 0.035 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "revenue": 3760, "activeUsers": 2150, "orders": 115, "conversion": 0.033 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "revenue": 3450, "activeUsers": 2120, "orders": 103, "conversion": 0.031 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "revenue": 4210, "activeUsers": 2230, "orders": 131, "conversion": 0.036 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "revenue": 4390, "activeUsers": 2290, "orders": 137, "conversion": 0.037 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "revenue": 4020, "activeUsers": 2270, "orders": 124, "conversion": 0.034 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "revenue": 3680, "activeUsers": 2240, "orders": 112, "conversion": 0.032 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "revenue": 4460, "activeUsers": 2330, "orders": 139, "conversion": 0.036 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "revenue": 4620, "activeUsers": 2390, "orders": 145, "conversion": 0.037 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "revenue": 4280, "activeUsers": 2360, "orders": 132, "conversion": 0.035 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "revenue": 3940, "activeUsers": 2340, "orders": 119, "conversion": 0.033 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "revenue": 4710, "activeUsers": 2420, "orders": 148, "conversion": 0.038 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "revenue": 4930, "activeUsers": 2480, "orders": 155, "conversion": 0.038 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "revenue": 4560, "activeUsers": 2460, "orders": 141, "conversion": 0.036 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "revenue": 4180, "activeUsers": 2430, "orders": 128, "conversion": 0.034 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "revenue": 5020, "activeUsers": 2510, "orders": 158, "conversion": 0.038 },
{ "date": new Date('2026-09-26T00:00:00.000Z'), "revenue": 5240, "activeUsers": 2570, "orders": 166, "conversion": 0.039 },
{ "date": new Date('2026-09-27T00:00:00.000Z'), "revenue": 4870, "activeUsers": 2550, "orders": 151, "conversion": 0.037 },
{ "date": new Date('2026-09-28T00:00:00.000Z'), "revenue": 4490, "activeUsers": 2520, "orders": 138, "conversion": 0.035 },
{ "date": new Date('2026-09-29T00:00:00.000Z'), "revenue": 5310, "activeUsers": 2610, "orders": 169, "conversion": 0.039 },
{ "date": new Date('2026-09-30T00:00:00.000Z'), "revenue": 5560, "activeUsers": 2680, "orders": 177, "conversion": 0.04 },
];
export function Example() {
return (
);
}
```
#### A rate
Rates average rather than add up: `aggregate="mean"` with a percent `valueFormat`.
```tsx
'use client';
import { StatCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const dailyKpis = [
{ "date": new Date('2026-09-01T00:00:00.000Z'), "revenue": 3120, "activeUsers": 1840, "orders": 96, "conversion": 0.031 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "revenue": 3380, "activeUsers": 1910, "orders": 104, "conversion": 0.033 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "revenue": 2940, "activeUsers": 1870, "orders": 88, "conversion": 0.029 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "revenue": 3510, "activeUsers": 1960, "orders": 110, "conversion": 0.034 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "revenue": 3720, "activeUsers": 2010, "orders": 118, "conversion": 0.035 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "revenue": 3290, "activeUsers": 1990, "orders": 101, "conversion": 0.032 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "revenue": 2860, "activeUsers": 1930, "orders": 84, "conversion": 0.028 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "revenue": 3640, "activeUsers": 2080, "orders": 112, "conversion": 0.033 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "revenue": 3910, "activeUsers": 2140, "orders": 121, "conversion": 0.036 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "revenue": 4080, "activeUsers": 2170, "orders": 126, "conversion": 0.035 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "revenue": 3760, "activeUsers": 2150, "orders": 115, "conversion": 0.033 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "revenue": 3450, "activeUsers": 2120, "orders": 103, "conversion": 0.031 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "revenue": 4210, "activeUsers": 2230, "orders": 131, "conversion": 0.036 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "revenue": 4390, "activeUsers": 2290, "orders": 137, "conversion": 0.037 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "revenue": 4020, "activeUsers": 2270, "orders": 124, "conversion": 0.034 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "revenue": 3680, "activeUsers": 2240, "orders": 112, "conversion": 0.032 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "revenue": 4460, "activeUsers": 2330, "orders": 139, "conversion": 0.036 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "revenue": 4620, "activeUsers": 2390, "orders": 145, "conversion": 0.037 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "revenue": 4280, "activeUsers": 2360, "orders": 132, "conversion": 0.035 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "revenue": 3940, "activeUsers": 2340, "orders": 119, "conversion": 0.033 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "revenue": 4710, "activeUsers": 2420, "orders": 148, "conversion": 0.038 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "revenue": 4930, "activeUsers": 2480, "orders": 155, "conversion": 0.038 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "revenue": 4560, "activeUsers": 2460, "orders": 141, "conversion": 0.036 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "revenue": 4180, "activeUsers": 2430, "orders": 128, "conversion": 0.034 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "revenue": 5020, "activeUsers": 2510, "orders": 158, "conversion": 0.038 },
{ "date": new Date('2026-09-26T00:00:00.000Z'), "revenue": 5240, "activeUsers": 2570, "orders": 166, "conversion": 0.039 },
{ "date": new Date('2026-09-27T00:00:00.000Z'), "revenue": 4870, "activeUsers": 2550, "orders": 151, "conversion": 0.037 },
{ "date": new Date('2026-09-28T00:00:00.000Z'), "revenue": 4490, "activeUsers": 2520, "orders": 138, "conversion": 0.035 },
{ "date": new Date('2026-09-29T00:00:00.000Z'), "revenue": 5310, "activeUsers": 2610, "orders": 169, "conversion": 0.039 },
{ "date": new Date('2026-09-30T00:00:00.000Z'), "revenue": 5560, "activeUsers": 2680, "orders": 177, "conversion": 0.04 },
];
export function Example() {
return (
);
}
```
#### Missing data
Week 5 was never reported, so the line breaks there and the total leaves it out. `null` is a gap, never zero.
```tsx
'use client';
import { StatCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const weeklySignups = [
{ "week": "W1", "signups": 412 },
{ "week": "W2", "signups": 468 },
{ "week": "W3", "signups": 455 },
{ "week": "W4", "signups": 503 },
{ "week": "W5", "signups": null },
{ "week": "W6", "signups": 544 },
{ "week": "W7", "signups": 596 },
{ "week": "W8", "signups": 571 },
{ "week": "W9", "signups": 638 },
{ "week": "W10", "signups": 662 },
{ "week": "W11", "signups": 701 },
{ "week": "W12", "signups": 689 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per observation. Several tiles can share the same rows.
const dailyKpis = [
{ date: new Date('2026-09-01'), revenue: 3120, activeUsers: 1840 },
{ date: new Date('2026-09-02'), revenue: 3380, activeUsers: 1910 },
];
// Already have the number? Pass it directly.
```
`value` names the numeric field to chart, and TypeScript rejects fields that don’t exist or aren’t numbers. The big number is that field summed over the rows; use `aggregate` for levels (`last`) or rates (`mean`). `x` is optional and only names points on hover. `null` is a gap in the chart and is left out of the summary, never counted as zero.
### Hover
Hovering the chart swaps the big number for that day’s reading and the change chip for its date, with Lilt’s hover dot on the line. Click to pin a point; with the chart focused, arrow keys move it.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Optional when you pass `headline`.
- `value` (`key of Row`): Numeric field to summarize and chart.
- `x` (`key of Row`): Text, number, or Date field that names each point on hover.
- `aggregate` (`'sum' | 'mean' | 'last' | 'max'`): How the big number summarizes the rows. Defaults to sum.
- `headline` (`number`): Set the resting number yourself.
- `delta` (`number`): Fractional change: 0.124 shows +12.4%.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good, such as churn.
- `caption` (`string`): Quiet text beside the change chip.
- `chart` (`'area' | 'line' | 'bars' | 'meter' | 'ring' | 'none'`): The small chart. Area by default; meter and ring fill toward `target`, the ring beside the value.
- `barStyle` (`'solid' | 'segmented' | 'needle' | 'gradient' | 'outline' | 'isometric'`): Bar treatment when `chart` is bars.
- `target` (`number`): Goal for the meter or ring, in the value’s unit.
- `sync` (`string`): Hover together with every card that shares this name, matched by x. Requires `x`.
- `height` (`number`): Chart height, and the ring’s size. 56 by default, 10 for a meter.
- `color` (`string`): Any CSS color for the chart.
- `aside` (`ReactNode`): Header content on the right, e.g. an icon.
- `depth` (`boolean`): Lines and the ring become lit tubes, the meter a solid bar, and bars default to `isometric`.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `formatX` (`(value: string | number | Date) => string`): Custom x label text.
- `xType` (`'category' | 'number' | 'time'`): Override inferred x type. Use time for numeric Unix timestamps in milliseconds.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
## Progress: `ProgressCard`
See how far you have come toward a goal. Docs: https://liltui.vercel.app/charts/progress
```tsx
import { ProgressCard } from '@lilt-ui/charts';
```
### Complete examples
#### Progress card
```tsx
'use client';
import { ProgressCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
export function Example() {
return (
);
}
```
#### Quarterly pace
Actual revenue meets a supplied plan at an explicit cutoff. Later actual values are excluded. Expected progress interpolates only between adjacent known plan readings.
```tsx
'use client';
import { GoalPacingCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const quarterlyPace = [
{ "day": 0, "actual": 0, "expected": 0 },
{ "day": 15, "actual": 12000, "expected": 9000 },
{ "day": 30, "actual": 24500, "expected": 22000 },
{ "day": 45, "actual": 41000, "expected": 36000 },
{ "day": 60, "actual": 56000, "expected": 55000 },
{ "day": 75, "actual": null, "expected": 77000 },
{ "day": 90, "actual": null, "expected": 100000 },
];
export function Example() {
return (
);
}
```
#### Release checkpoints
Named checkpoints keep their measured positions along one track. Completed, current, and upcoming states follow the supplied current value; null means unknown.
```tsx
'use client';
import { MilestoneProgressCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const releaseCheckpoints = [
{ "name": "Scope", "position": 0 },
{ "name": "Design", "position": 25 },
{ "name": "Build", "position": 55 },
{ "name": "QA", "position": 80 },
{ "name": "Launch", "position": 100 },
];
export function Example() {
return (
);
}
```
#### Past the goal
The ring stays full and the percentage keeps counting past 100%.
```tsx
'use client';
import { ProgressCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
export function Example() {
return (
);
}
```
#### Periods with their own goals
Each range can bring its own value, goal, and change.
```tsx
'use client';
import { ProgressCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
export function Example() {
return (
);
}
```
#### Not measured yet
A null value shows a dash and an empty track, never 0%.
```tsx
'use client';
import { ProgressCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
export function Example() {
return (
);
}
```
### Data
```tsx
// Plain numbers: the measured value and the goal, in the same unit.
// Not measured yet? null shows a dash and an empty track, never 0%.
// Summarizing rows yourself is one line.
const visitors = days.reduce((sum, day) => sum + day.visitors, 0);
```
Pass the value and the goal as numbers. The header shows the value in your `valueFormat`, and the ring shows the share of the goal reached. Past the goal the ring stays full and the percentage keeps counting, so 127% reads as 127%.
### Period select
```tsx
```
### Hover
The ring fills from the top when the card appears, and eases to the new amount when the period changes, while the percentage counts along. Screen readers hear the value, the percentage, and the target.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `value` (`number | null`): The measured amount. null shows a dash, never zero.
- `target` (`number`): The goal, in the value’s unit.
- `label` (`string`): Words under the percentage. “of goal” by default.
- `variant` (`'ring' | 'thick' | 'gauge'`): A thin ring (default), a heavy ring on a soft disc, or a half-ring gauge.
- `delta` (`number`): Fractional change for the chip.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label in the header.
- `ranges` (`{ id, label, value, target?, delta? }[]`): A period select. Each range brings its own value and, optionally, goal.
- `footer` (`ReactNode`): Content under the ring.
- `color` (`string`): Any CSS color for the progress.
- `depth` (`boolean`): Lights the fill as a tube in a groove cut into the card. The arc keeps its exact angle.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
### Goal pacing: GoalPacingCard
Actual revenue meets a supplied plan at an explicit cutoff. Later actual values are excluded. Expected progress interpolates only between adjacent known plan readings. All three loading styles share the skeleton exit, entrance, pointer/keyboard pinning, touch glide, reduced motion, and accessible readings table. Aggregate marks report null as their original datum.
```tsx
import { GoalPacingCard } from '@lilt-ui/charts';
```
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 260. Dense lanes expand to keep every mark visible.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Legend layout; false hides it. Correlation defaults to false.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Legend marker, square by default.
- `x` (`numeric key of Row`): Finite, unique elapsed periods.
- `actual` (`numeric keys of Row`): Supplied actual and planned measurements; the chart does not forecast.
- `expected` (`numeric keys of Row`): Supplied actual and planned measurements; the chart does not forecast.
- `at` (`number`): Current period, supplied explicitly.
- `target` (`number`): Positive goal on the same measurement scale.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
### Milestone progress: MilestoneProgressCard
Named checkpoints keep their measured positions along one track. Completed, current, and upcoming states follow the supplied current value; null means unknown. All three loading styles share the skeleton exit, entrance, pointer/keyboard pinning, touch glide, reduced motion, and accessible readings table. Aggregate marks report null as their original datum.
```tsx
import { MilestoneProgressCard } from '@lilt-ui/charts';
```
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 170px. Dense data may expand within the scrollable viewport.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Legend layout; false hides it. Correlation defaults to false.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Legend marker, square by default.
- `label` (`text key of Row`): Unique checkpoint name.
- `position` (`numeric key of Row`): Unique checkpoint position from zero through target.
- `current` (`number | null`): Current progress, including values beyond the target.
- `target` (`number`): Positive track endpoint, default 100.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Activity ring: `ActivityRingCard`
A full day of activity, wrapped into a ring. Docs: https://liltui.vercel.app/charts/activity-ring
```tsx
import { ActivityRingCard } from '@lilt-ui/charts';
```
### Complete examples
#### Activity ring card
```tsx
'use client';
import { ActivityRingCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "today", "label": "Today", "data": [
{ "hour": 0, "requests": 14 },
{ "hour": 0.6666666666666666, "requests": 20 },
{ "hour": 1.3333333333333333, "requests": 23 },
{ "hour": 2, "requests": 24 },
{ "hour": 2.6666666666666665, "requests": 21 },
{ "hour": 3.3333333333333335, "requests": 16 },
{ "hour": 4, "requests": 11 },
{ "hour": 4.666666666666667, "requests": 7 },
{ "hour": 5.333333333333333, "requests": 7 },
{ "hour": 6, "requests": 11 },
{ "hour": 6.666666666666667, "requests": 19 },
{ "hour": 7.333333333333333, "requests": 28 },
{ "hour": 8, "requests": 37 },
{ "hour": 8.666666666666666, "requests": 44 },
{ "hour": 9.333333333333334, "requests": 49 },
{ "hour": 10, "requests": 52 },
{ "hour": 10.666666666666666, "requests": 53 },
{ "hour": 11.333333333333334, "requests": 55 },
{ "hour": 12, "requests": 59 },
{ "hour": 12.666666666666666, "requests": 64 },
{ "hour": 13.333333333333334, "requests": 72 },
{ "hour": 14, "requests": 78 },
{ "hour": 14.666666666666666, "requests": 83 },
{ "hour": 15.333333333333334, "requests": 83 },
{ "hour": 16, "requests": 78 },
{ "hour": 16.666666666666668, "requests": 69 },
{ "hour": 17.333333333333332, "requests": 56 },
{ "hour": 18, "requests": 43 },
{ "hour": 18.666666666666668, "requests": 32 },
{ "hour": 19.333333333333332, "requests": 25 },
{ "hour": 20, "requests": 22 },
{ "hour": 20.666666666666668, "requests": 22 },
{ "hour": 21.333333333333332, "requests": 25 },
{ "hour": 22, "requests": 27 },
{ "hour": 22.666666666666668, "requests": 27 },
{ "hour": 23.333333333333332, "requests": 24 },
], "delta": 0.186 },
{ "id": "yesterday", "label": "Yesterday", "data": [
{ "hour": 0, "requests": 8 },
{ "hour": 0.6666666666666666, "requests": 14 },
{ "hour": 1.3333333333333333, "requests": 17 },
{ "hour": 2, "requests": 18 },
{ "hour": 2.6666666666666665, "requests": 15 },
{ "hour": 3.3333333333333335, "requests": 10 },
{ "hour": 4, "requests": 5 },
{ "hour": 4.666666666666667, "requests": 1 },
{ "hour": 5.333333333333333, "requests": 1 },
{ "hour": 6, "requests": 5 },
{ "hour": 6.666666666666667, "requests": 13 },
{ "hour": 7.333333333333333, "requests": 22 },
{ "hour": 8, "requests": 31 },
{ "hour": 8.666666666666666, "requests": 38 },
{ "hour": 9.333333333333334, "requests": 43 },
{ "hour": 10, "requests": 46 },
{ "hour": 10.666666666666666, "requests": 47 },
{ "hour": 11.333333333333334, "requests": 49 },
{ "hour": 12, "requests": 53 },
{ "hour": 12.666666666666666, "requests": 58 },
{ "hour": 13.333333333333334, "requests": 66 },
{ "hour": 14, "requests": 72 },
{ "hour": 14.666666666666666, "requests": 77 },
{ "hour": 15.333333333333334, "requests": 77 },
{ "hour": 16, "requests": 72 },
{ "hour": 16.666666666666668, "requests": 63 },
{ "hour": 17.333333333333332, "requests": 50 },
{ "hour": 18, "requests": 37 },
{ "hour": 18.666666666666668, "requests": 26 },
{ "hour": 19.333333333333332, "requests": 19 },
{ "hour": 20, "requests": 16 },
{ "hour": 20.666666666666668, "requests": 16 },
{ "hour": 21.333333333333332, "requests": 19 },
{ "hour": 22, "requests": 21 },
{ "hour": 22.666666666666668, "requests": 21 },
{ "hour": 23.333333333333332, "requests": 18 },
], "delta": -0.034 },
];
export function Example() {
return (
);
}
```
#### Hourly slots
The default `bucketMinutes` is 60, one slot per hour. `unit` names what the values count.
```tsx
'use client';
import { ActivityRingCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "Today", "data": [
{ "hour": 0, "tickets": 2 },
{ "hour": 1, "tickets": 1 },
{ "hour": 2, "tickets": 0 },
{ "hour": 3, "tickets": 0 },
{ "hour": 4, "tickets": 1 },
{ "hour": 5, "tickets": 2 },
{ "hour": 6, "tickets": 5 },
{ "hour": 7, "tickets": 11 },
{ "hour": 8, "tickets": 19 },
{ "hour": 9, "tickets": 26 },
{ "hour": 10, "tickets": 31 },
{ "hour": 11, "tickets": 28 },
{ "hour": 12, "tickets": 22 },
{ "hour": 13, "tickets": 24 },
{ "hour": 14, "tickets": 27 },
{ "hour": 15, "tickets": 23 },
{ "hour": 16, "tickets": 18 },
{ "hour": 17, "tickets": 13 },
{ "hour": 18, "tickets": 9 },
{ "hour": 19, "tickets": 7 },
{ "hour": 20, "tickets": 6 },
{ "hour": 21, "tickets": 4 },
{ "hour": 22, "tickets": 3 },
{ "hour": 23, "tickets": 2 },
] },
{ "id": "previous", "label": "Yesterday", "data": [
{ "hour": 0, "tickets": 2 },
{ "hour": 1, "tickets": 1 },
{ "hour": 2, "tickets": 0 },
{ "hour": 3, "tickets": 0 },
{ "hour": 3, "tickets": 1 },
{ "hour": 4, "tickets": 2 },
{ "hour": 5, "tickets": 4 },
{ "hour": 6, "tickets": 9 },
{ "hour": 7, "tickets": 16 },
{ "hour": 8, "tickets": 22 },
{ "hour": 9, "tickets": 27 },
{ "hour": 9, "tickets": 24 },
{ "hour": 10, "tickets": 19 },
{ "hour": 11, "tickets": 21 },
{ "hour": 12, "tickets": 23 },
{ "hour": 13, "tickets": 20 },
{ "hour": 14, "tickets": 15 },
{ "hour": 15, "tickets": 11 },
{ "hour": 15, "tickets": 8 },
{ "hour": 16, "tickets": 6 },
{ "hour": 17, "tickets": 5 },
{ "hour": 18, "tickets": 3 },
{ "hour": 19, "tickets": 3 },
{ "hour": 20, "tickets": 2 },
] },
];
export function Example() {
return (
);
}
```
#### Peak headline
`aggregate="max"` headlines the busiest slot instead of the total, for rates where a sum means little.
```tsx
'use client';
import { ActivityRingCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "Today", "data": [
{ "hour": 0, "requests": 14 },
{ "hour": 0.6666666666666666, "requests": 20 },
{ "hour": 1.3333333333333333, "requests": 23 },
{ "hour": 2, "requests": 24 },
{ "hour": 2.6666666666666665, "requests": 21 },
{ "hour": 3.3333333333333335, "requests": 16 },
{ "hour": 4, "requests": 11 },
{ "hour": 4.666666666666667, "requests": 7 },
{ "hour": 5.333333333333333, "requests": 7 },
{ "hour": 6, "requests": 11 },
{ "hour": 6.666666666666667, "requests": 19 },
{ "hour": 7.333333333333333, "requests": 28 },
{ "hour": 8, "requests": 37 },
{ "hour": 8.666666666666666, "requests": 44 },
{ "hour": 9.333333333333334, "requests": 49 },
{ "hour": 10, "requests": 52 },
{ "hour": 10.666666666666666, "requests": 53 },
{ "hour": 11.333333333333334, "requests": 55 },
{ "hour": 12, "requests": 59 },
{ "hour": 12.666666666666666, "requests": 64 },
{ "hour": 13.333333333333334, "requests": 72 },
{ "hour": 14, "requests": 78 },
{ "hour": 14.666666666666666, "requests": 83 },
{ "hour": 15.333333333333334, "requests": 83 },
{ "hour": 16, "requests": 78 },
{ "hour": 16.666666666666668, "requests": 69 },
{ "hour": 17.333333333333332, "requests": 56 },
{ "hour": 18, "requests": 43 },
{ "hour": 18.666666666666668, "requests": 32 },
{ "hour": 19.333333333333332, "requests": 25 },
{ "hour": 20, "requests": 22 },
{ "hour": 20.666666666666668, "requests": 22 },
{ "hour": 21.333333333333332, "requests": 25 },
{ "hour": 22, "requests": 27 },
{ "hour": 22.666666666666668, "requests": 27 },
{ "hour": 23.333333333333332, "requests": 24 },
] },
{ "id": "previous", "label": "Yesterday", "data": [
{ "hour": 0, "requests": 12 },
{ "hour": 0.57, "requests": 17 },
{ "hour": 1.15, "requests": 20 },
{ "hour": 2, "requests": 21 },
{ "hour": 2.29, "requests": 18 },
{ "hour": 2.87, "requests": 14 },
{ "hour": 3, "requests": 9 },
{ "hour": 4.01, "requests": 6 },
{ "hour": 4.59, "requests": 6 },
{ "hour": 5, "requests": 9 },
{ "hour": 5.73, "requests": 16 },
{ "hour": 6.31, "requests": 24 },
{ "hour": 7, "requests": 32 },
{ "hour": 7.45, "requests": 38 },
{ "hour": 8.03, "requests": 42 },
{ "hour": 9, "requests": 45 },
{ "hour": 9.17, "requests": 46 },
{ "hour": 9.75, "requests": 47 },
{ "hour": 10, "requests": 51 },
{ "hour": 10.89, "requests": 55 },
{ "hour": 11.47, "requests": 62 },
{ "hour": 12, "requests": 67 },
{ "hour": 12.61, "requests": 71 },
{ "hour": 13.19, "requests": 71 },
{ "hour": 14, "requests": 67 },
{ "hour": 14.33, "requests": 59 },
{ "hour": 14.91, "requests": 48 },
{ "hour": 15, "requests": 37 },
{ "hour": 16.05, "requests": 28 },
{ "hour": 16.63, "requests": 22 },
{ "hour": 17, "requests": 19 },
{ "hour": 17.77, "requests": 19 },
{ "hour": 18.35, "requests": 22 },
{ "hour": 19, "requests": 23 },
{ "hour": 19.49, "requests": 23 },
{ "hour": 20.07, "requests": 21 },
] },
];
export function Example() {
return (
);
}
```
#### Slots with no data
Logging was down from 02:40 to 04:00. Those slots stay empty and the footer counts them, while a measured quiet slot still shows its reading.
```tsx
'use client';
import { ActivityRingCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "Today", "data": [
{ "hour": 0, "requests": 14 },
{ "hour": 0.6666666666666666, "requests": 20 },
{ "hour": 1.3333333333333333, "requests": 23 },
{ "hour": 2, "requests": 24 },
{ "hour": 2.6666666666666665, "requests": null },
{ "hour": 3.3333333333333335, "requests": null },
{ "hour": 4, "requests": 11 },
{ "hour": 4.666666666666667, "requests": 7 },
{ "hour": 5.333333333333333, "requests": 7 },
{ "hour": 6, "requests": 11 },
{ "hour": 6.666666666666667, "requests": 19 },
{ "hour": 7.333333333333333, "requests": 28 },
{ "hour": 8, "requests": 37 },
{ "hour": 8.666666666666666, "requests": 44 },
{ "hour": 9.333333333333334, "requests": 49 },
{ "hour": 10, "requests": 52 },
{ "hour": 10.666666666666666, "requests": 53 },
{ "hour": 11.333333333333334, "requests": 55 },
{ "hour": 12, "requests": 59 },
{ "hour": 12.666666666666666, "requests": 64 },
{ "hour": 13.333333333333334, "requests": 72 },
{ "hour": 14, "requests": 78 },
{ "hour": 14.666666666666666, "requests": 83 },
{ "hour": 15.333333333333334, "requests": 83 },
{ "hour": 16, "requests": 78 },
{ "hour": 16.666666666666668, "requests": 69 },
{ "hour": 17.333333333333332, "requests": 56 },
{ "hour": 18, "requests": 43 },
{ "hour": 18.666666666666668, "requests": 32 },
{ "hour": 19.333333333333332, "requests": 25 },
{ "hour": 20, "requests": 22 },
{ "hour": 20.666666666666668, "requests": 22 },
{ "hour": 21.333333333333332, "requests": 25 },
{ "hour": 22, "requests": 27 },
{ "hour": 22.666666666666668, "requests": 27 },
{ "hour": 23.333333333333332, "requests": 24 },
] },
{ "id": "previous", "label": "Yesterday", "data": [
{ "hour": 0, "requests": 12 },
{ "hour": 0.57, "requests": 17 },
{ "hour": 1.15, "requests": 20 },
{ "hour": 2, "requests": 21 },
{ "hour": 2.29, "requests": null },
{ "hour": 2.87, "requests": null },
{ "hour": 3, "requests": 9 },
{ "hour": 4.01, "requests": 6 },
{ "hour": 4.59, "requests": 6 },
{ "hour": 5, "requests": 9 },
{ "hour": 5.73, "requests": 16 },
{ "hour": 6.31, "requests": 24 },
{ "hour": 7, "requests": 32 },
{ "hour": 7.45, "requests": 38 },
{ "hour": 8.03, "requests": 42 },
{ "hour": 9, "requests": 45 },
{ "hour": 9.17, "requests": 46 },
{ "hour": 9.75, "requests": 47 },
{ "hour": 10, "requests": 51 },
{ "hour": 10.89, "requests": 55 },
{ "hour": 11.47, "requests": 62 },
{ "hour": 12, "requests": 67 },
{ "hour": 12.61, "requests": 71 },
{ "hour": 13.19, "requests": 71 },
{ "hour": 14, "requests": 67 },
{ "hour": 14.33, "requests": 59 },
{ "hour": 14.91, "requests": 48 },
{ "hour": 15, "requests": 37 },
{ "hour": 16.05, "requests": 28 },
{ "hour": 16.63, "requests": 22 },
{ "hour": 17, "requests": 19 },
{ "hour": 17.77, "requests": 19 },
{ "hour": 18.35, "requests": 22 },
{ "hour": 19, "requests": 23 },
{ "hour": 19.49, "requests": 23 },
{ "hour": 20.07, "requests": 21 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per time slot; hour is the time of day, so 14.5 is 14:30.
const requestRhythm = [
{ hour: 0, requests: 14 },
{ hour: 0.6667, requests: 20 }, // 00:40
{ hour: 2.6667, requests: null }, // not recorded
// …
];
```
Each row is one time slot: `hour` places it around the day, clockwise from midnight at the top, and `value` fills its dots; TypeScript rejects anything but numeric fields. Every time must fall on a `bucketMinutes` slot, once. Dots fill against `maximum`, which defaults to a round number above the peak. A slot that is `null`, or has no row, stays empty and is counted in the footer, while a measured zero shows as a real reading, so an outage never looks like a quiet hour. The headline totals the day; `aggregate` switches it to the average or the peak.
### Period select
```tsx
```
### Hover
Hovering a slot reads it in the headline with its time, “14:40 · requests”, and the ring highlights it. Click to pin a slot. The ring is one tab stop: arrow keys step around the day, Enter pins, and Escape lets go. The center always shows the peak and when it happened, and the tiles name the busiest and quietest times.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per time slot. Omit when using ranges.
- `hour` (`numeric key of Row`): Time of day in hours, from 0 up to 24; 14.5 is 14:30.
- `value` (`numeric key of Row`): How much happened in the slot. `null` means not recorded.
- `bucketMinutes` (`number`): Minutes per slot. Must divide a day, like 15, 30, 40, or 60. Defaults to 60.
- `unit` (`string`): What `value` counts, e.g. “requests”. Defaults to the field name.
- `maximum` (`number`): Value that fills a slot’s dots. Defaults to a round number above the peak.
- `aggregate` (`'sum' | 'mean' | 'max'`): How the resting headline sums up the day. Sum by default.
- `height` (`number`): Ring height in pixels, at least 180. Defaults to 280.
- `headline` (`number`): Resting headline. Defaults to the aggregate of every recorded slot.
- `delta` (`number`): Fractional change for the chip.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label in the header.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the day.
- `color` (`string`): Any CSS color for the dots.
- `depth` (`boolean`): Turns each dot into a small lit puck.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
## Heatmap: `HeatmapChartCard`
Spot patterns and busy periods through color. Docs: https://liltui.vercel.app/charts/heatmap
```tsx
import { HeatmapChartCard } from '@lilt-ui/charts';
```
### Complete examples
#### Heatmap card
```tsx
'use client';
import { HeatmapChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "week", "label": "This week", "data": [
{ "day": "Mon", "hour": "00:00", "sessions": 0 },
{ "day": "Mon", "hour": "02:00", "sessions": 0 },
{ "day": "Mon", "hour": "04:00", "sessions": 0 },
{ "day": "Mon", "hour": "06:00", "sessions": 36 },
{ "day": "Mon", "hour": "08:00", "sessions": 166 },
{ "day": "Mon", "hour": "10:00", "sessions": 310 },
{ "day": "Mon", "hour": "12:00", "sessions": 402 },
{ "day": "Mon", "hour": "14:00", "sessions": 399 },
{ "day": "Mon", "hour": "16:00", "sessions": 309 },
{ "day": "Mon", "hour": "18:00", "sessions": 186 },
{ "day": "Mon", "hour": "20:00", "sessions": 82 },
{ "day": "Mon", "hour": "22:00", "sessions": 14 },
{ "day": "Tue", "hour": "00:00", "sessions": 0 },
{ "day": "Tue", "hour": "02:00", "sessions": 0 },
{ "day": "Tue", "hour": "04:00", "sessions": 0 },
{ "day": "Tue", "hour": "06:00", "sessions": 46 },
{ "day": "Tue", "hour": "08:00", "sessions": 207 },
{ "day": "Tue", "hour": "10:00", "sessions": 343 },
{ "day": "Tue", "hour": "12:00", "sessions": 397 },
{ "day": "Tue", "hour": "14:00", "sessions": 360 },
{ "day": "Tue", "hour": "16:00", "sessions": 273 },
{ "day": "Tue", "hour": "18:00", "sessions": 185 },
{ "day": "Tue", "hour": "20:00", "sessions": 118 },
{ "day": "Tue", "hour": "22:00", "sessions": 54 },
{ "day": "Wed", "hour": "00:00", "sessions": 0 },
{ "day": "Wed", "hour": "02:00", "sessions": 0 },
{ "day": "Wed", "hour": "04:00", "sessions": 0 },
{ "day": "Wed", "hour": "06:00", "sessions": 84 },
{ "day": "Wed", "hour": "08:00", "sessions": 245 },
{ "day": "Wed", "hour": "10:00", "sessions": 346 },
{ "day": "Wed", "hour": "12:00", "sessions": 363 },
{ "day": "Wed", "hour": "14:00", "sessions": 320 },
{ "day": "Wed", "hour": "16:00", "sessions": 263 },
{ "day": "Wed", "hour": "18:00", "sessions": 215 },
{ "day": "Wed", "hour": "20:00", "sessions": 160 },
{ "day": "Wed", "hour": "22:00", "sessions": 69 },
{ "day": "Thu", "hour": "00:00", "sessions": 0 },
{ "day": "Thu", "hour": "02:00", "sessions": 0 },
{ "day": "Thu", "hour": "04:00", "sessions": 0 },
{ "day": "Thu", "hour": "06:00", "sessions": 125 },
{ "day": "Thu", "hour": "08:00", "sessions": 257 },
{ "day": "Thu", "hour": "10:00", "sessions": 318 },
{ "day": "Thu", "hour": "12:00", "sessions": 321 },
{ "day": "Thu", "hour": "14:00", "sessions": 302 },
{ "day": "Thu", "hour": "16:00", "sessions": 286 },
{ "day": "Thu", "hour": "18:00", "sessions": 258 },
{ "day": "Thu", "hour": "20:00", "sessions": 183 },
{ "day": "Thu", "hour": "22:00", "sessions": 51 },
{ "day": "Fri", "hour": "00:00", "sessions": 0 },
{ "day": "Fri", "hour": "02:00", "sessions": 0 },
{ "day": "Fri", "hour": "04:00", "sessions": 4 },
{ "day": "Fri", "hour": "06:00", "sessions": 145 },
{ "day": "Fri", "hour": "08:00", "sessions": 236 },
{ "day": "Fri", "hour": "10:00", "sessions": 275 },
{ "day": "Fri", "hour": "12:00", "sessions": 295 },
{ "day": "Fri", "hour": "14:00", "sessions": 318 },
{ "day": "Fri", "hour": "16:00", "sessions": 328 },
{ "day": "Fri", "hour": "18:00", "sessions": 287 },
{ "day": "Fri", "hour": "20:00", "sessions": 173 },
{ "day": "Fri", "hour": "22:00", "sessions": 10 },
{ "day": "Sat", "hour": "00:00", "sessions": 0 },
{ "day": "Sat", "hour": "02:00", "sessions": 0 },
{ "day": "Sat", "hour": "04:00", "sessions": 14 },
{ "day": "Sat", "hour": "06:00", "sessions": 59 },
{ "day": "Sat", "hour": "08:00", "sessions": 87 },
{ "day": "Sat", "hour": "10:00", "sessions": 110 },
{ "day": "Sat", "hour": "12:00", "sessions": 136 },
{ "day": "Sat", "hour": "14:00", "sessions": 161 },
{ "day": "Sat", "hour": "16:00", "sessions": 164 },
{ "day": "Sat", "hour": "18:00", "sessions": 129 },
{ "day": "Sat", "hour": "20:00", "sessions": 61 },
{ "day": "Sat", "hour": "22:00", "sessions": 0 },
{ "day": "Sun", "hour": "00:00", "sessions": 0 },
{ "day": "Sun", "hour": "02:00", "sessions": 0 },
{ "day": "Sun", "hour": "04:00", "sessions": 12 },
{ "day": "Sun", "hour": "06:00", "sessions": 42 },
{ "day": "Sun", "hour": "08:00", "sessions": 71 },
{ "day": "Sun", "hour": "10:00", "sessions": 109 },
{ "day": "Sun", "hour": "12:00", "sessions": 152 },
{ "day": "Sun", "hour": "14:00", "sessions": 179 },
{ "day": "Sun", "hour": "16:00", "sessions": 167 },
{ "day": "Sun", "hour": "18:00", "sessions": 114 },
{ "day": "Sun", "hour": "20:00", "sessions": 43 },
{ "day": "Sun", "hour": "22:00", "sessions": 0 },
], "delta": 0.149 },
{ "id": "last-week", "label": "Last week", "data": [
{ "day": "Mon", "hour": "00:00", "sessions": 0 },
{ "day": "Mon", "hour": "02:00", "sessions": 0 },
{ "day": "Mon", "hour": "04:00", "sessions": 0 },
{ "day": "Mon", "hour": "06:00", "sessions": 8 },
{ "day": "Mon", "hour": "08:00", "sessions": 155 },
{ "day": "Mon", "hour": "10:00", "sessions": 302 },
{ "day": "Mon", "hour": "12:00", "sessions": 382 },
{ "day": "Mon", "hour": "14:00", "sessions": 362 },
{ "day": "Mon", "hour": "16:00", "sessions": 266 },
{ "day": "Mon", "hour": "18:00", "sessions": 153 },
{ "day": "Mon", "hour": "20:00", "sessions": 67 },
{ "day": "Mon", "hour": "22:00", "sessions": 7 },
{ "day": "Tue", "hour": "00:00", "sessions": 0 },
{ "day": "Tue", "hour": "02:00", "sessions": 0 },
{ "day": "Tue", "hour": "04:00", "sessions": 0 },
{ "day": "Tue", "hour": "06:00", "sessions": 35 },
{ "day": "Tue", "hour": "08:00", "sessions": 199 },
{ "day": "Tue", "hour": "10:00", "sessions": 323 },
{ "day": "Tue", "hour": "12:00", "sessions": 360 },
{ "day": "Tue", "hour": "14:00", "sessions": 317 },
{ "day": "Tue", "hour": "16:00", "sessions": 240 },
{ "day": "Tue", "hour": "18:00", "sessions": 169 },
{ "day": "Tue", "hour": "20:00", "sessions": 111 },
{ "day": "Tue", "hour": "22:00", "sessions": 38 },
{ "day": "Wed", "hour": "00:00", "sessions": 0 },
{ "day": "Wed", "hour": "02:00", "sessions": 0 },
{ "day": "Wed", "hour": "04:00", "sessions": 0 },
{ "day": "Wed", "hour": "06:00", "sessions": 76 },
{ "day": "Wed", "hour": "08:00", "sessions": 225 },
{ "day": "Wed", "hour": "10:00", "sessions": 309 },
{ "day": "Wed", "hour": "12:00", "sessions": 320 },
{ "day": "Wed", "hour": "14:00", "sessions": 287 },
{ "day": "Wed", "hour": "16:00", "sessions": 248 },
{ "day": "Wed", "hour": "18:00", "sessions": 208 },
{ "day": "Wed", "hour": "20:00", "sessions": 144 },
{ "day": "Wed", "hour": "22:00", "sessions": 36 },
{ "day": "Thu", "hour": "00:00", "sessions": 0 },
{ "day": "Thu", "hour": "02:00", "sessions": 0 },
{ "day": "Thu", "hour": "04:00", "sessions": 0 },
{ "day": "Thu", "hour": "06:00", "sessions": 105 },
{ "day": "Thu", "hour": "08:00", "sessions": 220 },
{ "day": "Thu", "hour": "10:00", "sessions": 275 },
{ "day": "Thu", "hour": "12:00", "sessions": 288 },
{ "day": "Thu", "hour": "14:00", "sessions": 287 },
{ "day": "Thu", "hour": "16:00", "sessions": 279 },
{ "day": "Thu", "hour": "18:00", "sessions": 242 },
{ "day": "Thu", "hour": "20:00", "sessions": 150 },
{ "day": "Thu", "hour": "22:00", "sessions": 8 },
{ "day": "Fri", "hour": "00:00", "sessions": 0 },
{ "day": "Fri", "hour": "02:00", "sessions": 0 },
{ "day": "Fri", "hour": "04:00", "sessions": 0 },
{ "day": "Fri", "hour": "06:00", "sessions": 108 },
{ "day": "Fri", "hour": "08:00", "sessions": 193 },
{ "day": "Fri", "hour": "10:00", "sessions": 243 },
{ "day": "Fri", "hour": "12:00", "sessions": 280 },
{ "day": "Fri", "hour": "14:00", "sessions": 311 },
{ "day": "Fri", "hour": "16:00", "sessions": 313 },
{ "day": "Fri", "hour": "18:00", "sessions": 255 },
{ "day": "Fri", "hour": "20:00", "sessions": 130 },
{ "day": "Fri", "hour": "22:00", "sessions": 0 },
{ "day": "Sat", "hour": "00:00", "sessions": 0 },
{ "day": "Sat", "hour": "02:00", "sessions": 0 },
{ "day": "Sat", "hour": "04:00", "sessions": 0 },
{ "day": "Sat", "hour": "06:00", "sessions": 16 },
{ "day": "Sat", "hour": "08:00", "sessions": 55 },
{ "day": "Sat", "hour": "10:00", "sessions": 94 },
{ "day": "Sat", "hour": "12:00", "sessions": 129 },
{ "day": "Sat", "hour": "14:00", "sessions": 145 },
{ "day": "Sat", "hour": "16:00", "sessions": 131 },
{ "day": "Sat", "hour": "18:00", "sessions": 86 },
{ "day": "Sat", "hour": "20:00", "sessions": 24 },
{ "day": "Sat", "hour": "22:00", "sessions": 0 },
{ "day": "Sun", "hour": "00:00", "sessions": 0 },
{ "day": "Sun", "hour": "02:00", "sessions": 0 },
{ "day": "Sun", "hour": "04:00", "sessions": 0 },
{ "day": "Sun", "hour": "06:00", "sessions": 9 },
{ "day": "Sun", "hour": "08:00", "sessions": 55 },
{ "day": "Sun", "hour": "10:00", "sessions": 102 },
{ "day": "Sun", "hour": "12:00", "sessions": 137 },
{ "day": "Sun", "hour": "14:00", "sessions": 146 },
{ "day": "Sun", "hour": "16:00", "sessions": 124 },
{ "day": "Sun", "hour": "18:00", "sessions": 77 },
{ "day": "Sun", "hour": "20:00", "sessions": 23 },
{ "day": "Sun", "hour": "22:00", "sessions": 0 },
], "delta": -0.021 },
];
export function Example() {
return (
);
}
```
#### Campaign relationships
A symmetric Pearson matrix compares each metric with every other metric. Inspection retains both rows and columns and reports the number of complete pairs. Constant values are undefined, not zero correlation.
```tsx
'use client';
import { CorrelationMatrixCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const campaignMetrics = [
{ "spend": 1200, "visits": 1090, "orders": 50, "churn": 14, "latency": 100 },
{ "spend": 1656.5883939231585, "visits": 1135.6198148536894, "orders": 76.42464787932029, "churn": 13.06321993654133, "latency": 134.52837466595494 },
{ "spend": 1803.7189707302728, "visits": 1129.6725534083535, "orders": 50.26455024751324, "churn": 11.185595810613826, "latency": 65.13696910345647 },
{ "spend": 1616.448003223947, "visits": 1091.9769284002487, "orders": 47.999181273768286, "churn": 9.651855715965878, "latency": 100.67255601937403 },
{ "spend": 1377.2790018768287, "visits": 1050.124759228686, "orders": 87.46069300468137, "churn": 9.486483167331706, "latency": 134.18395632353122 },
{ "spend": 1416.4302901347446, "visits": 1032.7255322687358, "orders": 84.06660667531864, "churn": 10.67840840113844, "latency": 64.8121696011332 },
{ "spend": 1808.2338007204296, "visits": 1062.401800815893, "orders": 58.41940293853719, "churn": 12.189385751885268, "latency": 101.34492188884553 },
{ "spend": 2302.7946394875157, "visits": 1150.250395050209, "orders": 85.739707038865, "churn": 12.73971727276683, "latency": 133.82987324571735 },
{ "spend": 2555.7432986493527, "visits": 1293.125530992733, "orders": 111.2444710840841, "churn": 11.77670262906451, "latency": 64.49731865673982 },
{ "spend": 2444.847394096703, "visits": 1474.4090081366128, "orders": 84.60671629923374, "churn": 9.892911692528418, "latency": 102.0169075122726 },
{ "spend": 2182.391555644252, "visits": 1668.0789245111744, "orders": 83.47828057102312, "churn": 8.377739476230646, "latency": 133.46622554144224 },
{ "spend": 2120.0039173797186, "visits": 1845.0807458299023, "orders": 122.90082222515632, "churn": 8.241617694749278, "latency": 64.19250528721273 },
{ "spend": 2425.370832799826, "visits": 1980.440868796088, "orders": 118.38751081640868, "churn": 9.45134018708933, "latency": 102.68832290101913 },
{ "spend": 2928.0668147306565, "visits": 2059.3810301747258, "orders": 93.28785772134572, "churn": 10.955192677307755, "latency": 133.09311602381513 },
{ "spend": 3276.2429422779483, "visits": 2080.936541042393, "orders": 121.47857759556045, "churn": 11.47886917100201, "latency": 63.897815671592525 },
{ "spend": 3260.115136062847, "visits": 2058.192476280406, "orders": 146.04027042489906, "churn": 10.489841326619786, "latency": 103.35897822766988 },
{ "spend": 3004.838673333974, "visits": 2015.0799918859327, "orders": 118.96063537754736, "churn": 8.600365287572489, "latency": 132.71065018105767 },
{ "spend": 2855.4410032481774, "visits": 1980.5171433556422, "orders": 118.97606310770495, "churn": 7.104138439171413, "latency": 63.61333312665887 },
{ "spend": 3059.6051012913294, "visits": 1981.3287371476777, "orders": 158.32070867677115, "churn": 6.9972550192755305, "latency": 104.02868387970031 },
{ "spend": 3539.950883865181, "visits": 2035.6786825128693, "orders": 152.69893011704656, "churn": 8.22438185775377, "latency": 132.3189361466794 },
{ "spend": 3965.178100291051, "visits": 2148.6228330216513, "orders": 128.18086522425145, "churn": 9.72063341648816, "latency": 63.33913808337465 },
{ "spend": 4054.6622554144224, "visits": 2310.8711372809616, "orders": 157.21577613383516, "churn": 10.217455934487003, "latency": 104.69725051308383 },
{ "spend": 3836.4594762838383, "visits": 2501.0621675171324, "orders": 180.81227681779197, "churn": 9.20264362362887, "latency": 131.91808466890524 },
{ "spend": 3621.511838329932, "visits": 2690.9931421007213, "orders": 153.32703808949552, "churn": 7.307965797501066, "latency": 63.07530806414562 },
{ "spend": 3717.7686551973507, "visits": 2852.524950095798, "orders": 154.49196597688655, "churn": 5.831056450171756, "latency": 105.36448910582656 },
{ "spend": 4147.059299960891, "visits": 2964.4715870028595, "orders": 193.7198775397506, "churn": 5.753390719812969, "latency": 131.50820907936472 },
{ "spend": 4625.023380191841, "visits": 3017.787227548047, "orders": 187.00164324425458, "churn": 6.99752407135163, "latency": 62.82191766090336 },
{ "spend": 4822.550371361801, "visits": 3017.780959194374, "orders": 163.09854643747266, "churn": 8.485700776636694, "latency": 106.03021101140676 },
{ "spend": 4668.362315323147, "visits": 2982.81693236988, "orders": 192.95046900820446, "churn": 8.955477962782261, "latency": 131.0894252610489 },
{ "spend": 4414.546446314813, "visits": 2939.818175970711, "orders": 215.56074808454514, "churn": 7.915117209623088, "latency": 62.57903851401529 },
];
export function Example() {
return (
);
}
```
#### Calendar
Daily activity across a quarter. Missing days are hatched; measured zero stays tinted. Use the site depth setting for raised tiles.
```tsx
'use client';
import { CalendarHeatmapCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This period", "data": [
{ "date": "2026-07-01", "visits": null },
{ "date": "2026-07-02", "visits": 337 },
{ "date": "2026-07-03", "visits": 474 },
{ "date": "2026-07-04", "visits": 611 },
{ "date": "2026-07-05", "visits": 748 },
{ "date": "2026-07-06", "visits": 885 },
{ "date": "2026-07-07", "visits": 1022 },
{ "date": "2026-07-08", "visits": 209 },
{ "date": "2026-07-09", "visits": 346 },
{ "date": "2026-07-10", "visits": 483 },
{ "date": "2026-07-11", "visits": 620 },
{ "date": "2026-07-12", "visits": 757 },
{ "date": "2026-07-13", "visits": 894 },
{ "date": "2026-07-14", "visits": 0 },
{ "date": "2026-07-15", "visits": 218 },
{ "date": "2026-07-16", "visits": 355 },
{ "date": "2026-07-17", "visits": 492 },
{ "date": "2026-07-18", "visits": 629 },
{ "date": "2026-07-19", "visits": 766 },
{ "date": "2026-07-20", "visits": null },
{ "date": "2026-07-21", "visits": 1040 },
{ "date": "2026-07-22", "visits": 227 },
{ "date": "2026-07-23", "visits": 364 },
{ "date": "2026-07-24", "visits": 501 },
{ "date": "2026-07-25", "visits": 638 },
{ "date": "2026-07-26", "visits": 775 },
{ "date": "2026-07-27", "visits": 0 },
{ "date": "2026-07-28", "visits": 1049 },
{ "date": "2026-07-29", "visits": 236 },
{ "date": "2026-07-30", "visits": 373 },
{ "date": "2026-07-31", "visits": 510 },
{ "date": "2026-08-01", "visits": 647 },
{ "date": "2026-08-02", "visits": 784 },
{ "date": "2026-08-03", "visits": 921 },
{ "date": "2026-08-04", "visits": 1058 },
{ "date": "2026-08-05", "visits": 245 },
{ "date": "2026-08-06", "visits": 382 },
{ "date": "2026-08-07", "visits": 519 },
{ "date": "2026-08-08", "visits": null },
{ "date": "2026-08-09", "visits": 0 },
{ "date": "2026-08-10", "visits": 930 },
{ "date": "2026-08-11", "visits": 1067 },
{ "date": "2026-08-12", "visits": 254 },
{ "date": "2026-08-13", "visits": 391 },
{ "date": "2026-08-14", "visits": 528 },
{ "date": "2026-08-15", "visits": 665 },
{ "date": "2026-08-16", "visits": 802 },
{ "date": "2026-08-17", "visits": 939 },
{ "date": "2026-08-18", "visits": 1076 },
{ "date": "2026-08-19", "visits": 263 },
{ "date": "2026-08-20", "visits": 400 },
{ "date": "2026-08-21", "visits": 537 },
{ "date": "2026-08-22", "visits": 0 },
{ "date": "2026-08-23", "visits": 811 },
{ "date": "2026-08-24", "visits": 948 },
{ "date": "2026-08-25", "visits": 1085 },
{ "date": "2026-08-26", "visits": 272 },
{ "date": "2026-08-27", "visits": null },
{ "date": "2026-08-28", "visits": 546 },
{ "date": "2026-08-29", "visits": 683 },
{ "date": "2026-08-30", "visits": 820 },
{ "date": "2026-08-31", "visits": 957 },
{ "date": "2026-09-01", "visits": 1094 },
{ "date": "2026-09-02", "visits": 281 },
{ "date": "2026-09-03", "visits": 418 },
{ "date": "2026-09-04", "visits": 0 },
{ "date": "2026-09-05", "visits": 692 },
{ "date": "2026-09-06", "visits": 829 },
{ "date": "2026-09-07", "visits": 966 },
{ "date": "2026-09-08", "visits": 1103 },
{ "date": "2026-09-09", "visits": 290 },
{ "date": "2026-09-10", "visits": 427 },
{ "date": "2026-09-11", "visits": 564 },
{ "date": "2026-09-12", "visits": 701 },
{ "date": "2026-09-13", "visits": 838 },
{ "date": "2026-09-14", "visits": 975 },
{ "date": "2026-09-15", "visits": null },
{ "date": "2026-09-16", "visits": 299 },
{ "date": "2026-09-17", "visits": 0 },
{ "date": "2026-09-18", "visits": 573 },
{ "date": "2026-09-19", "visits": 710 },
{ "date": "2026-09-20", "visits": 847 },
{ "date": "2026-09-21", "visits": 984 },
{ "date": "2026-09-22", "visits": 1121 },
{ "date": "2026-09-23", "visits": 308 },
{ "date": "2026-09-24", "visits": 445 },
{ "date": "2026-09-25", "visits": 582 },
{ "date": "2026-09-26", "visits": 719 },
{ "date": "2026-09-27", "visits": 856 },
{ "date": "2026-09-28", "visits": 993 },
{ "date": "2026-09-29", "visits": 1130 },
{ "date": "2026-09-30", "visits": 0 },
] },
{ "id": "previous", "label": "Last period", "data": [
{ "date": "2026-07-01", "visits": null },
{ "date": "2026-07-02", "visits": 290 },
{ "date": "2026-07-03", "visits": 408 },
{ "date": "2026-07-04", "visits": 525 },
{ "date": "2026-07-05", "visits": 643 },
{ "date": "2026-07-06", "visits": 761 },
{ "date": "2026-07-07", "visits": 879 },
{ "date": "2026-07-08", "visits": 180 },
{ "date": "2026-07-09", "visits": 298 },
{ "date": "2026-07-10", "visits": 415 },
{ "date": "2026-07-11", "visits": 533 },
{ "date": "2026-07-12", "visits": 651 },
{ "date": "2026-07-13", "visits": 769 },
{ "date": "2026-07-14", "visits": 0 },
{ "date": "2026-07-15", "visits": 187 },
{ "date": "2026-07-16", "visits": 305 },
{ "date": "2026-07-17", "visits": 423 },
{ "date": "2026-07-18", "visits": 541 },
{ "date": "2026-07-19", "visits": 659 },
{ "date": "2026-07-20", "visits": null },
{ "date": "2026-07-21", "visits": 894 },
{ "date": "2026-07-22", "visits": 195 },
{ "date": "2026-07-23", "visits": 313 },
{ "date": "2026-07-24", "visits": 431 },
{ "date": "2026-07-25", "visits": 549 },
{ "date": "2026-07-26", "visits": 667 },
{ "date": "2026-07-27", "visits": 0 },
{ "date": "2026-07-28", "visits": 902 },
{ "date": "2026-07-29", "visits": 203 },
{ "date": "2026-07-30", "visits": 321 },
{ "date": "2026-07-31", "visits": 439 },
{ "date": "2026-08-01", "visits": 556 },
{ "date": "2026-08-02", "visits": 674 },
{ "date": "2026-08-03", "visits": 792 },
{ "date": "2026-08-04", "visits": 910 },
{ "date": "2026-08-05", "visits": 211 },
{ "date": "2026-08-06", "visits": 329 },
{ "date": "2026-08-07", "visits": 446 },
{ "date": "2026-08-08", "visits": null },
{ "date": "2026-08-09", "visits": 0 },
{ "date": "2026-08-10", "visits": 800 },
{ "date": "2026-08-11", "visits": 918 },
{ "date": "2026-08-12", "visits": 218 },
{ "date": "2026-08-13", "visits": 336 },
{ "date": "2026-08-14", "visits": 454 },
{ "date": "2026-08-15", "visits": 572 },
{ "date": "2026-08-16", "visits": 690 },
{ "date": "2026-08-17", "visits": 808 },
{ "date": "2026-08-18", "visits": 925 },
{ "date": "2026-08-19", "visits": 226 },
{ "date": "2026-08-20", "visits": 344 },
{ "date": "2026-08-21", "visits": 462 },
{ "date": "2026-08-22", "visits": 0 },
{ "date": "2026-08-23", "visits": 697 },
{ "date": "2026-08-24", "visits": 815 },
{ "date": "2026-08-25", "visits": 933 },
{ "date": "2026-08-26", "visits": 234 },
{ "date": "2026-08-27", "visits": null },
{ "date": "2026-08-28", "visits": 470 },
{ "date": "2026-08-29", "visits": 587 },
{ "date": "2026-08-30", "visits": 705 },
{ "date": "2026-08-31", "visits": 823 },
{ "date": "2026-09-01", "visits": 941 },
{ "date": "2026-09-02", "visits": 242 },
{ "date": "2026-09-03", "visits": 359 },
{ "date": "2026-09-04", "visits": 0 },
{ "date": "2026-09-05", "visits": 595 },
{ "date": "2026-09-06", "visits": 713 },
{ "date": "2026-09-07", "visits": 831 },
{ "date": "2026-09-08", "visits": 949 },
{ "date": "2026-09-09", "visits": 249 },
{ "date": "2026-09-10", "visits": 367 },
{ "date": "2026-09-11", "visits": 485 },
{ "date": "2026-09-12", "visits": 603 },
{ "date": "2026-09-13", "visits": 721 },
{ "date": "2026-09-14", "visits": 839 },
{ "date": "2026-09-15", "visits": null },
{ "date": "2026-09-16", "visits": 257 },
{ "date": "2026-09-17", "visits": 0 },
{ "date": "2026-09-18", "visits": 493 },
{ "date": "2026-09-19", "visits": 611 },
{ "date": "2026-09-20", "visits": 728 },
{ "date": "2026-09-21", "visits": 846 },
{ "date": "2026-09-22", "visits": 964 },
{ "date": "2026-09-23", "visits": 265 },
{ "date": "2026-09-24", "visits": 383 },
{ "date": "2026-09-25", "visits": 501 },
{ "date": "2026-09-26", "visits": 618 },
{ "date": "2026-09-27", "visits": 736 },
{ "date": "2026-09-28", "visits": 854 },
{ "date": "2026-09-29", "visits": 972 },
{ "date": "2026-09-30", "visits": 0 },
] },
];
export function Example() {
return (
);
}
```
#### Retention cohorts
Each row is a month of sign-ups, each column a week after. Newer cohorts haven’t reached their later weeks, so those cells read “No data” rather than zero. A fixed `domain` from 0 to 1 keeps the colors honest, and `aggregate="mean"` headlines the average.
```tsx
'use client';
import { HeatmapChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This week", "data": [
{ "cohort": "Apr", "week": "Week 1", "retained": 0.62 },
{ "cohort": "Apr", "week": "Week 2", "retained": 0.503 },
{ "cohort": "Apr", "week": "Week 3", "retained": 0.407 },
{ "cohort": "Apr", "week": "Week 4", "retained": 0.33 },
{ "cohort": "Apr", "week": "Week 5", "retained": 0.268 },
{ "cohort": "Apr", "week": "Week 6", "retained": 0.217 },
{ "cohort": "May", "week": "Week 1", "retained": 0.645 },
{ "cohort": "May", "week": "Week 2", "retained": 0.523 },
{ "cohort": "May", "week": "Week 3", "retained": 0.424 },
{ "cohort": "May", "week": "Week 4", "retained": 0.344 },
{ "cohort": "May", "week": "Week 5", "retained": 0.278 },
{ "cohort": "May", "week": "Week 6", "retained": null },
{ "cohort": "Jun", "week": "Week 1", "retained": 0.67 },
{ "cohort": "Jun", "week": "Week 2", "retained": 0.543 },
{ "cohort": "Jun", "week": "Week 3", "retained": 0.44 },
{ "cohort": "Jun", "week": "Week 4", "retained": 0.357 },
{ "cohort": "Jun", "week": "Week 5", "retained": null },
{ "cohort": "Jun", "week": "Week 6", "retained": null },
{ "cohort": "Jul", "week": "Week 1", "retained": 0.695 },
{ "cohort": "Jul", "week": "Week 2", "retained": 0.563 },
{ "cohort": "Jul", "week": "Week 3", "retained": 0.457 },
{ "cohort": "Jul", "week": "Week 4", "retained": null },
{ "cohort": "Jul", "week": "Week 5", "retained": null },
{ "cohort": "Jul", "week": "Week 6", "retained": null },
{ "cohort": "Aug", "week": "Week 1", "retained": 0.72 },
{ "cohort": "Aug", "week": "Week 2", "retained": 0.584 },
{ "cohort": "Aug", "week": "Week 3", "retained": null },
{ "cohort": "Aug", "week": "Week 4", "retained": null },
{ "cohort": "Aug", "week": "Week 5", "retained": null },
{ "cohort": "Aug", "week": "Week 6", "retained": null },
{ "cohort": "Sep", "week": "Week 1", "retained": 0.745 },
{ "cohort": "Sep", "week": "Week 2", "retained": null },
{ "cohort": "Sep", "week": "Week 3", "retained": null },
{ "cohort": "Sep", "week": "Week 4", "retained": null },
{ "cohort": "Sep", "week": "Week 5", "retained": null },
{ "cohort": "Sep", "week": "Week 6", "retained": null },
] },
{ "id": "previous", "label": "Last week", "data": [
{ "cohort": "Apr", "week": "Week 1", "retained": 0.53 },
{ "cohort": "Apr", "week": "Week 2", "retained": 0.43 },
{ "cohort": "Apr", "week": "Week 3", "retained": 0.35 },
{ "cohort": "Apr", "week": "Week 4", "retained": 0.28 },
{ "cohort": "Apr", "week": "Week 5", "retained": 0.23 },
{ "cohort": "Apr", "week": "Week 6", "retained": 0.19 },
{ "cohort": "May", "week": "Week 1", "retained": 0.55 },
{ "cohort": "May", "week": "Week 2", "retained": 0.45 },
{ "cohort": "May", "week": "Week 3", "retained": 0.36 },
{ "cohort": "May", "week": "Week 4", "retained": 0.3 },
{ "cohort": "May", "week": "Week 5", "retained": 0.24 },
{ "cohort": "May", "week": "Week 6", "retained": null },
{ "cohort": "Jun", "week": "Week 1", "retained": 0.58 },
{ "cohort": "Jun", "week": "Week 2", "retained": 0.47 },
{ "cohort": "Jun", "week": "Week 3", "retained": 0.38 },
{ "cohort": "Jun", "week": "Week 4", "retained": 0.31 },
{ "cohort": "Jun", "week": "Week 5", "retained": null },
{ "cohort": "Jun", "week": "Week 6", "retained": null },
{ "cohort": "Jul", "week": "Week 1", "retained": 0.6 },
{ "cohort": "Jul", "week": "Week 2", "retained": 0.48 },
{ "cohort": "Jul", "week": "Week 3", "retained": 0.39 },
{ "cohort": "Jul", "week": "Week 4", "retained": null },
{ "cohort": "Jul", "week": "Week 5", "retained": null },
{ "cohort": "Jul", "week": "Week 6", "retained": null },
{ "cohort": "Aug", "week": "Week 1", "retained": 0.62 },
{ "cohort": "Aug", "week": "Week 2", "retained": 0.5 },
{ "cohort": "Aug", "week": "Week 3", "retained": null },
{ "cohort": "Aug", "week": "Week 4", "retained": null },
{ "cohort": "Aug", "week": "Week 5", "retained": null },
{ "cohort": "Aug", "week": "Week 6", "retained": null },
{ "cohort": "Sep", "week": "Week 1", "retained": 0.64 },
{ "cohort": "Sep", "week": "Week 2", "retained": null },
{ "cohort": "Sep", "week": "Week 3", "retained": null },
{ "cohort": "Sep", "week": "Week 4", "retained": null },
{ "cohort": "Sep", "week": "Week 5", "retained": null },
{ "cohort": "Sep", "week": "Week 6", "retained": null },
] },
];
export function Example() {
return (
);
}
```
#### Cells with no data
Tracking was down on three mornings and on Sunday evening. Those cells are hatched and say “No data”, the footer keys the hatch, and the headline counts only what was recorded.
```tsx
'use client';
import { HeatmapChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This week", "data": [
{ "day": "Mon", "hour": "00:00", "sessions": 0 },
{ "day": "Mon", "hour": "02:00", "sessions": 0 },
{ "day": "Mon", "hour": "04:00", "sessions": 0 },
{ "day": "Mon", "hour": "06:00", "sessions": 36 },
{ "day": "Mon", "hour": "08:00", "sessions": 166 },
{ "day": "Mon", "hour": "10:00", "sessions": null },
{ "day": "Mon", "hour": "12:00", "sessions": 402 },
{ "day": "Mon", "hour": "14:00", "sessions": 399 },
{ "day": "Mon", "hour": "16:00", "sessions": 309 },
{ "day": "Mon", "hour": "18:00", "sessions": 186 },
{ "day": "Mon", "hour": "20:00", "sessions": 82 },
{ "day": "Mon", "hour": "22:00", "sessions": 14 },
{ "day": "Tue", "hour": "00:00", "sessions": 0 },
{ "day": "Tue", "hour": "02:00", "sessions": 0 },
{ "day": "Tue", "hour": "04:00", "sessions": 0 },
{ "day": "Tue", "hour": "06:00", "sessions": 46 },
{ "day": "Tue", "hour": "08:00", "sessions": 207 },
{ "day": "Tue", "hour": "10:00", "sessions": null },
{ "day": "Tue", "hour": "12:00", "sessions": 397 },
{ "day": "Tue", "hour": "14:00", "sessions": 360 },
{ "day": "Tue", "hour": "16:00", "sessions": 273 },
{ "day": "Tue", "hour": "18:00", "sessions": 185 },
{ "day": "Tue", "hour": "20:00", "sessions": 118 },
{ "day": "Tue", "hour": "22:00", "sessions": 54 },
{ "day": "Wed", "hour": "00:00", "sessions": 0 },
{ "day": "Wed", "hour": "02:00", "sessions": 0 },
{ "day": "Wed", "hour": "04:00", "sessions": 0 },
{ "day": "Wed", "hour": "06:00", "sessions": 84 },
{ "day": "Wed", "hour": "08:00", "sessions": 245 },
{ "day": "Wed", "hour": "10:00", "sessions": null },
{ "day": "Wed", "hour": "12:00", "sessions": 363 },
{ "day": "Wed", "hour": "14:00", "sessions": 320 },
{ "day": "Wed", "hour": "16:00", "sessions": 263 },
{ "day": "Wed", "hour": "18:00", "sessions": 215 },
{ "day": "Wed", "hour": "20:00", "sessions": 160 },
{ "day": "Wed", "hour": "22:00", "sessions": 69 },
{ "day": "Thu", "hour": "00:00", "sessions": 0 },
{ "day": "Thu", "hour": "02:00", "sessions": 0 },
{ "day": "Thu", "hour": "04:00", "sessions": 0 },
{ "day": "Thu", "hour": "06:00", "sessions": 125 },
{ "day": "Thu", "hour": "08:00", "sessions": 257 },
{ "day": "Thu", "hour": "10:00", "sessions": 318 },
{ "day": "Thu", "hour": "12:00", "sessions": 321 },
{ "day": "Thu", "hour": "14:00", "sessions": 302 },
{ "day": "Thu", "hour": "16:00", "sessions": 286 },
{ "day": "Thu", "hour": "18:00", "sessions": 258 },
{ "day": "Thu", "hour": "20:00", "sessions": 183 },
{ "day": "Thu", "hour": "22:00", "sessions": 51 },
{ "day": "Fri", "hour": "00:00", "sessions": 0 },
{ "day": "Fri", "hour": "02:00", "sessions": 0 },
{ "day": "Fri", "hour": "04:00", "sessions": 4 },
{ "day": "Fri", "hour": "06:00", "sessions": 145 },
{ "day": "Fri", "hour": "08:00", "sessions": 236 },
{ "day": "Fri", "hour": "10:00", "sessions": 275 },
{ "day": "Fri", "hour": "12:00", "sessions": 295 },
{ "day": "Fri", "hour": "14:00", "sessions": 318 },
{ "day": "Fri", "hour": "16:00", "sessions": 328 },
{ "day": "Fri", "hour": "18:00", "sessions": 287 },
{ "day": "Fri", "hour": "20:00", "sessions": 173 },
{ "day": "Fri", "hour": "22:00", "sessions": 10 },
{ "day": "Sat", "hour": "00:00", "sessions": 0 },
{ "day": "Sat", "hour": "02:00", "sessions": 0 },
{ "day": "Sat", "hour": "04:00", "sessions": 14 },
{ "day": "Sat", "hour": "06:00", "sessions": 59 },
{ "day": "Sat", "hour": "08:00", "sessions": 87 },
{ "day": "Sat", "hour": "10:00", "sessions": 110 },
{ "day": "Sat", "hour": "12:00", "sessions": 136 },
{ "day": "Sat", "hour": "14:00", "sessions": 161 },
{ "day": "Sat", "hour": "16:00", "sessions": 164 },
{ "day": "Sat", "hour": "18:00", "sessions": 129 },
{ "day": "Sat", "hour": "20:00", "sessions": 61 },
{ "day": "Sat", "hour": "22:00", "sessions": 0 },
{ "day": "Sun", "hour": "00:00", "sessions": 0 },
{ "day": "Sun", "hour": "02:00", "sessions": 0 },
{ "day": "Sun", "hour": "04:00", "sessions": 12 },
{ "day": "Sun", "hour": "06:00", "sessions": 42 },
{ "day": "Sun", "hour": "08:00", "sessions": 71 },
{ "day": "Sun", "hour": "10:00", "sessions": 109 },
{ "day": "Sun", "hour": "12:00", "sessions": 152 },
{ "day": "Sun", "hour": "14:00", "sessions": 179 },
{ "day": "Sun", "hour": "16:00", "sessions": 167 },
{ "day": "Sun", "hour": "18:00", "sessions": null },
{ "day": "Sun", "hour": "20:00", "sessions": 43 },
{ "day": "Sun", "hour": "22:00", "sessions": 0 },
] },
{ "id": "previous", "label": "Last week", "data": [
{ "day": "Mon", "hour": "00:00", "sessions": 0 },
{ "day": "Mon", "hour": "02:00", "sessions": 0 },
{ "day": "Mon", "hour": "04:00", "sessions": 0 },
{ "day": "Mon", "hour": "06:00", "sessions": 31 },
{ "day": "Mon", "hour": "08:00", "sessions": 143 },
{ "day": "Mon", "hour": "10:00", "sessions": null },
{ "day": "Mon", "hour": "12:00", "sessions": 346 },
{ "day": "Mon", "hour": "14:00", "sessions": 343 },
{ "day": "Mon", "hour": "16:00", "sessions": 266 },
{ "day": "Mon", "hour": "18:00", "sessions": 160 },
{ "day": "Mon", "hour": "20:00", "sessions": 71 },
{ "day": "Mon", "hour": "22:00", "sessions": 12 },
{ "day": "Tue", "hour": "00:00", "sessions": 0 },
{ "day": "Tue", "hour": "02:00", "sessions": 0 },
{ "day": "Tue", "hour": "04:00", "sessions": 0 },
{ "day": "Tue", "hour": "06:00", "sessions": 40 },
{ "day": "Tue", "hour": "08:00", "sessions": 178 },
{ "day": "Tue", "hour": "10:00", "sessions": null },
{ "day": "Tue", "hour": "12:00", "sessions": 341 },
{ "day": "Tue", "hour": "14:00", "sessions": 310 },
{ "day": "Tue", "hour": "16:00", "sessions": 235 },
{ "day": "Tue", "hour": "18:00", "sessions": 159 },
{ "day": "Tue", "hour": "20:00", "sessions": 101 },
{ "day": "Tue", "hour": "22:00", "sessions": 46 },
{ "day": "Wed", "hour": "00:00", "sessions": 0 },
{ "day": "Wed", "hour": "02:00", "sessions": 0 },
{ "day": "Wed", "hour": "04:00", "sessions": 0 },
{ "day": "Wed", "hour": "06:00", "sessions": 72 },
{ "day": "Wed", "hour": "08:00", "sessions": 211 },
{ "day": "Wed", "hour": "10:00", "sessions": null },
{ "day": "Wed", "hour": "12:00", "sessions": 312 },
{ "day": "Wed", "hour": "14:00", "sessions": 275 },
{ "day": "Wed", "hour": "16:00", "sessions": 226 },
{ "day": "Wed", "hour": "18:00", "sessions": 185 },
{ "day": "Wed", "hour": "20:00", "sessions": 138 },
{ "day": "Wed", "hour": "22:00", "sessions": 59 },
{ "day": "Thu", "hour": "00:00", "sessions": 0 },
{ "day": "Thu", "hour": "02:00", "sessions": 0 },
{ "day": "Thu", "hour": "04:00", "sessions": 0 },
{ "day": "Thu", "hour": "06:00", "sessions": 108 },
{ "day": "Thu", "hour": "08:00", "sessions": 221 },
{ "day": "Thu", "hour": "10:00", "sessions": 273 },
{ "day": "Thu", "hour": "12:00", "sessions": 276 },
{ "day": "Thu", "hour": "14:00", "sessions": 260 },
{ "day": "Thu", "hour": "16:00", "sessions": 246 },
{ "day": "Thu", "hour": "18:00", "sessions": 222 },
{ "day": "Thu", "hour": "20:00", "sessions": 157 },
{ "day": "Thu", "hour": "22:00", "sessions": 44 },
{ "day": "Fri", "hour": "00:00", "sessions": 0 },
{ "day": "Fri", "hour": "02:00", "sessions": 0 },
{ "day": "Fri", "hour": "04:00", "sessions": 3 },
{ "day": "Fri", "hour": "06:00", "sessions": 125 },
{ "day": "Fri", "hour": "08:00", "sessions": 203 },
{ "day": "Fri", "hour": "10:00", "sessions": 237 },
{ "day": "Fri", "hour": "12:00", "sessions": 254 },
{ "day": "Fri", "hour": "14:00", "sessions": 273 },
{ "day": "Fri", "hour": "16:00", "sessions": 282 },
{ "day": "Fri", "hour": "18:00", "sessions": 247 },
{ "day": "Fri", "hour": "20:00", "sessions": 149 },
{ "day": "Fri", "hour": "22:00", "sessions": 9 },
{ "day": "Sat", "hour": "00:00", "sessions": 0 },
{ "day": "Sat", "hour": "02:00", "sessions": 0 },
{ "day": "Sat", "hour": "04:00", "sessions": 12 },
{ "day": "Sat", "hour": "06:00", "sessions": 51 },
{ "day": "Sat", "hour": "08:00", "sessions": 75 },
{ "day": "Sat", "hour": "10:00", "sessions": 95 },
{ "day": "Sat", "hour": "12:00", "sessions": 117 },
{ "day": "Sat", "hour": "14:00", "sessions": 138 },
{ "day": "Sat", "hour": "16:00", "sessions": 141 },
{ "day": "Sat", "hour": "18:00", "sessions": 111 },
{ "day": "Sat", "hour": "20:00", "sessions": 52 },
{ "day": "Sat", "hour": "22:00", "sessions": 0 },
{ "day": "Sun", "hour": "00:00", "sessions": 0 },
{ "day": "Sun", "hour": "02:00", "sessions": 0 },
{ "day": "Sun", "hour": "04:00", "sessions": 10 },
{ "day": "Sun", "hour": "06:00", "sessions": 36 },
{ "day": "Sun", "hour": "08:00", "sessions": 61 },
{ "day": "Sun", "hour": "10:00", "sessions": 94 },
{ "day": "Sun", "hour": "12:00", "sessions": 131 },
{ "day": "Sun", "hour": "14:00", "sessions": 154 },
{ "day": "Sun", "hour": "16:00", "sessions": 144 },
{ "day": "Sun", "hour": "18:00", "sessions": null },
{ "day": "Sun", "hour": "20:00", "sessions": 37 },
{ "day": "Sun", "hour": "22:00", "sessions": 0 },
] },
];
export function Example() {
return (
);
}
```
#### Fixed scale
By default the darkest cell is this period’s busiest. Pass `domain` to hold the scale steady, so two weeks, or two cards side by side, color the same value the same way.
```tsx
'use client';
import { HeatmapChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This week", "data": [
{ "day": "Mon", "hour": "00:00", "sessions": 0 },
{ "day": "Mon", "hour": "02:00", "sessions": 0 },
{ "day": "Mon", "hour": "04:00", "sessions": 0 },
{ "day": "Mon", "hour": "06:00", "sessions": 36 },
{ "day": "Mon", "hour": "08:00", "sessions": 166 },
{ "day": "Mon", "hour": "10:00", "sessions": 310 },
{ "day": "Mon", "hour": "12:00", "sessions": 402 },
{ "day": "Mon", "hour": "14:00", "sessions": 399 },
{ "day": "Mon", "hour": "16:00", "sessions": 309 },
{ "day": "Mon", "hour": "18:00", "sessions": 186 },
{ "day": "Mon", "hour": "20:00", "sessions": 82 },
{ "day": "Mon", "hour": "22:00", "sessions": 14 },
{ "day": "Tue", "hour": "00:00", "sessions": 0 },
{ "day": "Tue", "hour": "02:00", "sessions": 0 },
{ "day": "Tue", "hour": "04:00", "sessions": 0 },
{ "day": "Tue", "hour": "06:00", "sessions": 46 },
{ "day": "Tue", "hour": "08:00", "sessions": 207 },
{ "day": "Tue", "hour": "10:00", "sessions": 343 },
{ "day": "Tue", "hour": "12:00", "sessions": 397 },
{ "day": "Tue", "hour": "14:00", "sessions": 360 },
{ "day": "Tue", "hour": "16:00", "sessions": 273 },
{ "day": "Tue", "hour": "18:00", "sessions": 185 },
{ "day": "Tue", "hour": "20:00", "sessions": 118 },
{ "day": "Tue", "hour": "22:00", "sessions": 54 },
{ "day": "Wed", "hour": "00:00", "sessions": 0 },
{ "day": "Wed", "hour": "02:00", "sessions": 0 },
{ "day": "Wed", "hour": "04:00", "sessions": 0 },
{ "day": "Wed", "hour": "06:00", "sessions": 84 },
{ "day": "Wed", "hour": "08:00", "sessions": 245 },
{ "day": "Wed", "hour": "10:00", "sessions": 346 },
{ "day": "Wed", "hour": "12:00", "sessions": 363 },
{ "day": "Wed", "hour": "14:00", "sessions": 320 },
{ "day": "Wed", "hour": "16:00", "sessions": 263 },
{ "day": "Wed", "hour": "18:00", "sessions": 215 },
{ "day": "Wed", "hour": "20:00", "sessions": 160 },
{ "day": "Wed", "hour": "22:00", "sessions": 69 },
{ "day": "Thu", "hour": "00:00", "sessions": 0 },
{ "day": "Thu", "hour": "02:00", "sessions": 0 },
{ "day": "Thu", "hour": "04:00", "sessions": 0 },
{ "day": "Thu", "hour": "06:00", "sessions": 125 },
{ "day": "Thu", "hour": "08:00", "sessions": 257 },
{ "day": "Thu", "hour": "10:00", "sessions": 318 },
{ "day": "Thu", "hour": "12:00", "sessions": 321 },
{ "day": "Thu", "hour": "14:00", "sessions": 302 },
{ "day": "Thu", "hour": "16:00", "sessions": 286 },
{ "day": "Thu", "hour": "18:00", "sessions": 258 },
{ "day": "Thu", "hour": "20:00", "sessions": 183 },
{ "day": "Thu", "hour": "22:00", "sessions": 51 },
{ "day": "Fri", "hour": "00:00", "sessions": 0 },
{ "day": "Fri", "hour": "02:00", "sessions": 0 },
{ "day": "Fri", "hour": "04:00", "sessions": 4 },
{ "day": "Fri", "hour": "06:00", "sessions": 145 },
{ "day": "Fri", "hour": "08:00", "sessions": 236 },
{ "day": "Fri", "hour": "10:00", "sessions": 275 },
{ "day": "Fri", "hour": "12:00", "sessions": 295 },
{ "day": "Fri", "hour": "14:00", "sessions": 318 },
{ "day": "Fri", "hour": "16:00", "sessions": 328 },
{ "day": "Fri", "hour": "18:00", "sessions": 287 },
{ "day": "Fri", "hour": "20:00", "sessions": 173 },
{ "day": "Fri", "hour": "22:00", "sessions": 10 },
{ "day": "Sat", "hour": "00:00", "sessions": 0 },
{ "day": "Sat", "hour": "02:00", "sessions": 0 },
{ "day": "Sat", "hour": "04:00", "sessions": 14 },
{ "day": "Sat", "hour": "06:00", "sessions": 59 },
{ "day": "Sat", "hour": "08:00", "sessions": 87 },
{ "day": "Sat", "hour": "10:00", "sessions": 110 },
{ "day": "Sat", "hour": "12:00", "sessions": 136 },
{ "day": "Sat", "hour": "14:00", "sessions": 161 },
{ "day": "Sat", "hour": "16:00", "sessions": 164 },
{ "day": "Sat", "hour": "18:00", "sessions": 129 },
{ "day": "Sat", "hour": "20:00", "sessions": 61 },
{ "day": "Sat", "hour": "22:00", "sessions": 0 },
{ "day": "Sun", "hour": "00:00", "sessions": 0 },
{ "day": "Sun", "hour": "02:00", "sessions": 0 },
{ "day": "Sun", "hour": "04:00", "sessions": 12 },
{ "day": "Sun", "hour": "06:00", "sessions": 42 },
{ "day": "Sun", "hour": "08:00", "sessions": 71 },
{ "day": "Sun", "hour": "10:00", "sessions": 109 },
{ "day": "Sun", "hour": "12:00", "sessions": 152 },
{ "day": "Sun", "hour": "14:00", "sessions": 179 },
{ "day": "Sun", "hour": "16:00", "sessions": 167 },
{ "day": "Sun", "hour": "18:00", "sessions": 114 },
{ "day": "Sun", "hour": "20:00", "sessions": 43 },
{ "day": "Sun", "hour": "22:00", "sessions": 0 },
] },
{ "id": "previous", "label": "Last week", "data": [
{ "day": "Mon", "hour": "00:00", "sessions": 0 },
{ "day": "Mon", "hour": "02:00", "sessions": 0 },
{ "day": "Mon", "hour": "04:00", "sessions": 0 },
{ "day": "Mon", "hour": "06:00", "sessions": 31 },
{ "day": "Mon", "hour": "08:00", "sessions": 143 },
{ "day": "Mon", "hour": "10:00", "sessions": 267 },
{ "day": "Mon", "hour": "12:00", "sessions": 346 },
{ "day": "Mon", "hour": "14:00", "sessions": 343 },
{ "day": "Mon", "hour": "16:00", "sessions": 266 },
{ "day": "Mon", "hour": "18:00", "sessions": 160 },
{ "day": "Mon", "hour": "20:00", "sessions": 71 },
{ "day": "Mon", "hour": "22:00", "sessions": 12 },
{ "day": "Tue", "hour": "00:00", "sessions": 0 },
{ "day": "Tue", "hour": "02:00", "sessions": 0 },
{ "day": "Tue", "hour": "04:00", "sessions": 0 },
{ "day": "Tue", "hour": "06:00", "sessions": 40 },
{ "day": "Tue", "hour": "08:00", "sessions": 178 },
{ "day": "Tue", "hour": "10:00", "sessions": 295 },
{ "day": "Tue", "hour": "12:00", "sessions": 341 },
{ "day": "Tue", "hour": "14:00", "sessions": 310 },
{ "day": "Tue", "hour": "16:00", "sessions": 235 },
{ "day": "Tue", "hour": "18:00", "sessions": 159 },
{ "day": "Tue", "hour": "20:00", "sessions": 101 },
{ "day": "Tue", "hour": "22:00", "sessions": 46 },
{ "day": "Wed", "hour": "00:00", "sessions": 0 },
{ "day": "Wed", "hour": "02:00", "sessions": 0 },
{ "day": "Wed", "hour": "04:00", "sessions": 0 },
{ "day": "Wed", "hour": "06:00", "sessions": 72 },
{ "day": "Wed", "hour": "08:00", "sessions": 211 },
{ "day": "Wed", "hour": "10:00", "sessions": 298 },
{ "day": "Wed", "hour": "12:00", "sessions": 312 },
{ "day": "Wed", "hour": "14:00", "sessions": 275 },
{ "day": "Wed", "hour": "16:00", "sessions": 226 },
{ "day": "Wed", "hour": "18:00", "sessions": 185 },
{ "day": "Wed", "hour": "20:00", "sessions": 138 },
{ "day": "Wed", "hour": "22:00", "sessions": 59 },
{ "day": "Thu", "hour": "00:00", "sessions": 0 },
{ "day": "Thu", "hour": "02:00", "sessions": 0 },
{ "day": "Thu", "hour": "04:00", "sessions": 0 },
{ "day": "Thu", "hour": "06:00", "sessions": 108 },
{ "day": "Thu", "hour": "08:00", "sessions": 221 },
{ "day": "Thu", "hour": "10:00", "sessions": 273 },
{ "day": "Thu", "hour": "12:00", "sessions": 276 },
{ "day": "Thu", "hour": "14:00", "sessions": 260 },
{ "day": "Thu", "hour": "16:00", "sessions": 246 },
{ "day": "Thu", "hour": "18:00", "sessions": 222 },
{ "day": "Thu", "hour": "20:00", "sessions": 157 },
{ "day": "Thu", "hour": "22:00", "sessions": 44 },
{ "day": "Fri", "hour": "00:00", "sessions": 0 },
{ "day": "Fri", "hour": "02:00", "sessions": 0 },
{ "day": "Fri", "hour": "04:00", "sessions": 3 },
{ "day": "Fri", "hour": "06:00", "sessions": 125 },
{ "day": "Fri", "hour": "08:00", "sessions": 203 },
{ "day": "Fri", "hour": "10:00", "sessions": 237 },
{ "day": "Fri", "hour": "12:00", "sessions": 254 },
{ "day": "Fri", "hour": "14:00", "sessions": 273 },
{ "day": "Fri", "hour": "16:00", "sessions": 282 },
{ "day": "Fri", "hour": "18:00", "sessions": 247 },
{ "day": "Fri", "hour": "20:00", "sessions": 149 },
{ "day": "Fri", "hour": "22:00", "sessions": 9 },
{ "day": "Sat", "hour": "00:00", "sessions": 0 },
{ "day": "Sat", "hour": "02:00", "sessions": 0 },
{ "day": "Sat", "hour": "04:00", "sessions": 12 },
{ "day": "Sat", "hour": "06:00", "sessions": 51 },
{ "day": "Sat", "hour": "08:00", "sessions": 75 },
{ "day": "Sat", "hour": "10:00", "sessions": 95 },
{ "day": "Sat", "hour": "12:00", "sessions": 117 },
{ "day": "Sat", "hour": "14:00", "sessions": 138 },
{ "day": "Sat", "hour": "16:00", "sessions": 141 },
{ "day": "Sat", "hour": "18:00", "sessions": 111 },
{ "day": "Sat", "hour": "20:00", "sessions": 52 },
{ "day": "Sat", "hour": "22:00", "sessions": 0 },
{ "day": "Sun", "hour": "00:00", "sessions": 0 },
{ "day": "Sun", "hour": "02:00", "sessions": 0 },
{ "day": "Sun", "hour": "04:00", "sessions": 10 },
{ "day": "Sun", "hour": "06:00", "sessions": 36 },
{ "day": "Sun", "hour": "08:00", "sessions": 61 },
{ "day": "Sun", "hour": "10:00", "sessions": 94 },
{ "day": "Sun", "hour": "12:00", "sessions": 131 },
{ "day": "Sun", "hour": "14:00", "sessions": 154 },
{ "day": "Sun", "hour": "16:00", "sessions": 144 },
{ "day": "Sun", "hour": "18:00", "sessions": 98 },
{ "day": "Sun", "hour": "20:00", "sessions": 37 },
{ "day": "Sun", "hour": "22:00", "sessions": 0 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per cell: which column, which row, and its value.
const weeklyActivity = [
{ day: 'Mon', hour: '00:00', sessions: 12 },
{ day: 'Mon', hour: '02:00', sessions: 0 },
{ day: 'Mon', hour: '10:00', sessions: null }, // not recorded
// …
];
```
Each row is one cell: `x` names its column, `y` its row, and `value` sets its color; TypeScript rejects anything else. Rows and columns keep the order they first appear, or pass `rows` and `columns` to set it. A cell that is `null`, or has no row at all, is hatched and reads “No data”, while a measured zero gets the lightest tint, so a gap never passes for a quiet hour. The headline is the sum of every known cell; `aggregate` switches it to a mean or max for rates.
### Period select
```tsx
```
### Hover
Hovering or focusing a cell counts the headline to its value and names it beside the number: “Tue · 14:00”. Its row and column stay lit, their labels darken, and the rest of the grid dims. Click to pin a cell. The grid is one tab stop: arrow keys move between cells, Home and End jump along the row, and Escape unpins. Cells fade in on first view and ease to their new color when the period changes.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per cell. Omit when using ranges.
- `x` (`text key of Row`): Places each cell in a column.
- `y` (`text key of Row`): Places each cell in a row.
- `value` (`numeric key of Row`): Sets the color. `null`, or a cell with no row, reads “No data”.
- `columns` (`string[]`): Column order. Defaults to the order columns first appear.
- `rows` (`string[]`): Row order. Defaults to the order rows first appear.
- `domain` (`[number, number]`): Values at the light and dark ends of the scale. Fix it to compare periods; defaults to zero through the highest value.
- `aggregate` (`'sum' | 'mean' | 'max'`): How the resting headline sums up the cells. Sum by default.
- `height` (`number`): Grid height in pixels, shared by the rows. Defaults to 30 per row.
- `radius` (`number`): Cell corner radius in pixels. Defaults to 5; 0 gives square cells.
- `gap` (`number`): Space between cells in pixels. Defaults to 4.
- `headline` (`number`): Resting headline. Defaults to the aggregate of every known cell.
- `delta` (`number`): Fractional change for the chip.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label in the header.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the cells.
- `color` (`string`): Any CSS color for the dark end of the scale.
- `depth` (`boolean`): Raises every cell as a low tile of one height with a lit top. Color alone still carries the value.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
### Correlation matrix: CorrelationMatrixCard
A symmetric Pearson matrix compares each metric with every other metric. Inspection retains both rows and columns and reports the number of complete pairs. Constant values are undefined, not zero correlation. All three loading styles share the skeleton exit, entrance, pointer/keyboard pinning, touch glide, reduced motion, and accessible readings table. Aggregate marks report null as their original datum.
```tsx
import { CorrelationMatrixCard } from '@lilt-ui/charts';
```
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 260. Dense lanes expand to keep every mark visible.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Legend layout; false hides it. Correlation defaults to false.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Legend marker, square by default.
- `metrics` (`CardSeries[]`): At least two distinct numeric metrics.
- `minPairs` (`number`): Minimum complete pairs for a coefficient, default 3.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
### Calendar heatmap: CalendarHeatmapCard
CalendarHeatmapCard lays out one UTC day per cell. Bounds default to the observed dates. Duplicate days are rejected; aggregate them first. Zero stays tinted, absent days are hatched, and unobserved days after today are outlined. Wide calendars scroll on narrow screens. All loading styles fade out through the shared skeleton lifecycle.
```tsx
import { CalendarHeatmapCard } from '@lilt-ui/charts';
```
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 260. Dense lanes expand to keep every mark visible.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `date` (`date, string, or numeric key of Row`): UTC date per cell; numbers are milliseconds since the Unix epoch.
- `value` (`numeric key of Row`): Cell intensity and headline value.
- `from` (`string | number | Date`): Inclusive UTC bounds. Defaults to first and last observed dates; at most ten years.
- `to` (`string | number | Date`): Inclusive UTC bounds. Defaults to first and last observed dates; at most ten years.
- `today` (`string | number | Date`): UTC cutoff for future cells; defaults to today.
- `weekStartsOn` (`0 | 1`): Sunday (0) or Monday (1, default).
- `domain` (`[number, number]`): Fixed intensity domain that must contain every value.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Scatter chart: `ScatterChartCard`
Explore relationships between two measurements. Docs: https://liltui.vercel.app/charts/scatter
```tsx
import { ScatterChartCard } from '@lilt-ui/charts';
```
### Complete examples
#### Scatter chart card
```tsx
'use client';
import { ScatterChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "quarter", "label": "This quarter", "data": [
{ "campaign": "Brand search", "channel": "Search", "spend": 4200, "signups": 610, "reach": 18000 },
{ "campaign": "Competitor terms", "channel": "Search", "spend": 9800, "signups": 720, "reach": 22000 },
{ "campaign": "Product search", "channel": "Search", "spend": 14500, "signups": 1380, "reach": 31000 },
{ "campaign": "Shopping ads", "channel": "Search", "spend": 21000, "signups": 1690, "reach": 42000 },
{ "campaign": "Generic terms", "channel": "Search", "spend": 27500, "signups": 1540, "reach": 50000 },
{ "campaign": "Launch video", "channel": "Social", "spend": 6400, "signups": 290, "reach": 64000 },
{ "campaign": "Creator series", "channel": "Social", "spend": 12800, "signups": 820, "reach": 71000 },
{ "campaign": "Carousel ads", "channel": "Social", "spend": 18200, "signups": 760, "reach": 48000 },
{ "campaign": "Story ads", "channel": "Social", "spend": 24600, "signups": 1120, "reach": 83000 },
{ "campaign": "Lookalike audiences", "channel": "Social", "spend": 33800, "signups": 1470, "reach": 96000 },
{ "campaign": "Welcome series", "channel": "Email", "spend": 1800, "signups": 540, "reach": 9000 },
{ "campaign": "Newsletter feature", "channel": "Email", "spend": 3100, "signups": 460, "reach": 14000 },
{ "campaign": "Win-back", "channel": "Email", "spend": 5200, "signups": 830, "reach": 12000 },
{ "campaign": "Partner list", "channel": "Email", "spend": 8600, "signups": 690, "reach": 21000 },
], "delta": 0.198 },
{ "id": "last-quarter", "label": "Last quarter", "data": [
{ "campaign": "Brand search", "channel": "Search", "spend": 3276, "signups": 427, "reach": 18000 },
{ "campaign": "Competitor terms", "channel": "Search", "spend": 8134, "signups": 634, "reach": 22000 },
{ "campaign": "Product search", "channel": "Search", "spend": 12760, "signups": 1049, "reach": 31000 },
{ "campaign": "Shopping ads", "channel": "Search", "spend": 19530, "signups": 1589, "reach": 42000 },
{ "campaign": "Generic terms", "channel": "Search", "spend": 21450, "signups": 1263, "reach": 50000 },
{ "campaign": "Launch video", "channel": "Social", "spend": 5312, "signups": 203, "reach": 64000 },
{ "campaign": "Creator series", "channel": "Social", "spend": 11264, "signups": 722, "reach": 71000 },
{ "campaign": "Carousel ads", "channel": "Social", "spend": 16926, "signups": 578, "reach": 48000 },
{ "campaign": "Story ads", "channel": "Social", "spend": 19188, "signups": 1053, "reach": 83000 },
{ "campaign": "Lookalike audiences", "channel": "Social", "spend": 28054, "signups": 1205, "reach": 96000 },
{ "campaign": "Welcome series", "channel": "Email", "spend": 1584, "signups": 378, "reach": 9000 },
{ "campaign": "Newsletter feature", "channel": "Email", "spend": 2883, "signups": 405, "reach": 14000 },
{ "campaign": "Win-back", "channel": "Email", "spend": 4056, "signups": 631, "reach": 12000 },
{ "campaign": "Partner list", "channel": "Email", "spend": 7138, "signups": 649, "reach": 21000 },
], "delta": 0.074 },
];
export function Example() {
return (
);
}
```
#### Market trajectories
Each market moves through seven quarters. Trails follow explicit time order, break at missing positions, and retain their whole group while an observation is pinned.
```tsx
'use client';
import { ScatterChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This quarter", "data": [
{ "market": "North", "quarter": 0, "reading": "North · Q1", "reach": 20, "retention": 41 },
{ "market": "North", "quarter": 1, "reading": "North · Q2", "reach": 28.365883939231587, "retention": 42.180240256082996 },
{ "market": "North", "quarter": 2, "reading": "North · Q3", "reach": 33.637189707302724, "retention": 40.824802866192265 },
{ "market": "North", "quarter": 3, "reading": "North · Q4", "reach": 35.564480032239466, "retention": 39.575637706752524 },
{ "market": "North", "quarter": 4, "reading": "North · Q5", "reach": 36.972790018768286, "retention": 41.01023134523148 },
{ "market": "North", "quarter": 5, "reading": "North · Q6", "reach": 41.16430290134745, "retention": 46.07813827481833 },
{ "market": "North", "quarter": 6, "reading": "North · Q7", "reach": 48.8823380072043, "retention": 53.52499390063668 },
{ "market": "South", "quarter": 0, "reading": "South · Q1", "reach": 37.36588393923159, "retention": 46.24181383520884 },
{ "market": "South", "quarter": 1, "reading": "South · Q2", "reach": 42.637189707302724, "retention": 44.636787431841476 },
{ "market": "South", "quarter": 2, "reading": "South · Q3", "reach": 44.564480032239466, "retention": 43.85866747978632 },
{ "market": "South", "quarter": 3, "reading": "South · Q4", "reach": 45.972790018768286, "retention": 46.199210844523236 },
{ "market": "South", "quarter": 4, "reading": "South · Q5", "reach": 50.16430290134745, "retention": 52.058435071955806 },
{ "market": "South", "quarter": 5, "reading": "South · Q6", "reach": 57.8823380072043, "retention": 59.701973112779356 },
{ "market": "South", "quarter": 6, "reading": "South · Q7", "reach": 66.62794639487515, "retention": 66.31311710164792 },
{ "market": "West", "quarter": 0, "reading": "West · Q1", "reach": 51.637189707302724, "retention": 48.50311898071715 },
{ "market": "West", "quarter": 1, "reading": "West · Q2", "reach": 53.564480032239466, "retention": 48.34666595598805 },
{ "market": "West", "quarter": 2, "reading": "West · Q3", "reach": 54.972790018768286, "retention": 51.61944950199512 },
{ "market": "West", "quarter": 3, "reading": "West · Q4", "reach": 59.16430290134745, "retention": 58.156002780129484 },
{ "market": "West", "quarter": 4, "reading": "West · Q5", "reach": 66.8823380072043, "retention": 65.81110002780227 },
{ "market": "West", "quarter": 5, "reading": "West · Q6", "reach": 75.62794639487515, "retention": 71.7610217199022 },
{ "market": "West", "quarter": 6, "reading": "West · Q7", "reach": 81.95743298649353, "retention": 74.21638494209895 },
] },
{ "id": "previous", "label": "Last quarter", "data": [
{ "market": "North", "quarter": 0, "reading": "North · Q1", "reach": 20, "retention": 35 },
{ "market": "North", "quarter": 1, "reading": "North · Q2", "reach": 28.365883939231587, "retention": 36.28 },
{ "market": "North", "quarter": 2, "reading": "North · Q3", "reach": 33.637189707302724, "retention": 35.11 },
{ "market": "North", "quarter": 3, "reading": "North · Q4", "reach": 35.564480032239466, "retention": 34.04 },
{ "market": "North", "quarter": 3, "reading": "North · Q5", "reach": 36.972790018768286, "retention": 35.27 },
{ "market": "North", "quarter": 4, "reading": "North · Q6", "reach": 41.16430290134745, "retention": 39.63 },
{ "market": "North", "quarter": 5, "reading": "North · Q7", "reach": 48.8823380072043, "retention": 46.03 },
{ "market": "South", "quarter": 0, "reading": "South · Q1", "reach": 37.36588393923159, "retention": 39.77 },
{ "market": "South", "quarter": 1, "reading": "South · Q2", "reach": 42.637189707302724, "retention": 38.39 },
{ "market": "South", "quarter": 2, "reading": "South · Q3", "reach": 44.564480032239466, "retention": 37.72 },
{ "market": "South", "quarter": 3, "reading": "South · Q4", "reach": 45.972790018768286, "retention": 39.73 },
{ "market": "South", "quarter": 3, "reading": "South · Q5", "reach": 50.16430290134745, "retention": 44.77 },
{ "market": "South", "quarter": 4, "reading": "South · Q6", "reach": 57.8823380072043, "retention": 51.34 },
{ "market": "South", "quarter": 5, "reading": "South · Q7", "reach": 66.62794639487515, "retention": 57.03 },
{ "market": "West", "quarter": 0, "reading": "West · Q1", "reach": 51.637189707302724, "retention": 41.71 },
{ "market": "West", "quarter": 1, "reading": "West · Q2", "reach": 53.564480032239466, "retention": 41.58 },
{ "market": "West", "quarter": 2, "reading": "West · Q3", "reach": 54.972790018768286, "retention": 44.39 },
{ "market": "West", "quarter": 3, "reading": "West · Q4", "reach": 59.16430290134745, "retention": 50.01 },
{ "market": "West", "quarter": 3, "reading": "West · Q5", "reach": 66.8823380072043, "retention": 56.6 },
{ "market": "West", "quarter": 4, "reading": "West · Q6", "reach": 75.62794639487515, "retention": 61.71 },
{ "market": "West", "quarter": 5, "reading": "West · Q7", "reach": 81.95743298649353, "retention": 63.83 },
] },
];
export function Example() {
return (
);
}
```
#### Beeswarm
Points spread across each category to avoid collisions. Their measured positions stay exact; depth renders each point as a sphere.
```tsx
'use client';
import { StripChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This period", "data": [
{ "parcel": "Express 1", "carrier": "Express", "hours": 8 },
{ "parcel": "Express 2", "carrier": "Express", "hours": 15.5 },
{ "parcel": "Express 3", "carrier": "Express", "hours": 23 },
{ "parcel": "Express 4", "carrier": "Express", "hours": 11.5 },
{ "parcel": "Express 5", "carrier": "Express", "hours": 17 },
{ "parcel": "Express 6", "carrier": "Express", "hours": 24.5 },
{ "parcel": "Express 7", "carrier": "Express", "hours": 13 },
{ "parcel": "Express 8", "carrier": "Express", "hours": 20.5 },
{ "parcel": "Express 9", "carrier": "Express", "hours": 26 },
{ "parcel": "Express 10", "carrier": "Express", "hours": 14.5 },
{ "parcel": "Express 11", "carrier": "Express", "hours": 22 },
{ "parcel": "Express 12", "carrier": "Express", "hours": 10.5 },
{ "parcel": "Express 13", "carrier": "Express", "hours": 16 },
{ "parcel": "Express 14", "carrier": "Express", "hours": 23.5 },
{ "parcel": "Express 15", "carrier": "Express", "hours": 12 },
{ "parcel": "Express 16", "carrier": "Express", "hours": 19.5 },
{ "parcel": "Express 17", "carrier": "Express", "hours": 25 },
{ "parcel": "Express 18", "carrier": "Express", "hours": 13.5 },
{ "parcel": "Express 19", "carrier": "Express", "hours": 21 },
{ "parcel": "Express 20", "carrier": "Express", "hours": 9.5 },
{ "parcel": "Express 21", "carrier": "Express", "hours": 15 },
{ "parcel": "Express 22", "carrier": "Express", "hours": 22.5 },
{ "parcel": "Express 23", "carrier": "Express", "hours": 11 },
{ "parcel": "Express 24", "carrier": "Express", "hours": 18.5 },
{ "parcel": "Standard 1", "carrier": "Standard", "hours": 22 },
{ "parcel": "Standard 2", "carrier": "Standard", "hours": 29.5 },
{ "parcel": "Standard 3", "carrier": "Standard", "hours": 37 },
{ "parcel": "Standard 4", "carrier": "Standard", "hours": 25.5 },
{ "parcel": "Standard 5", "carrier": "Standard", "hours": 31 },
{ "parcel": "Standard 6", "carrier": "Standard", "hours": 38.5 },
{ "parcel": "Standard 7", "carrier": "Standard", "hours": 27 },
{ "parcel": "Standard 8", "carrier": "Standard", "hours": 34.5 },
{ "parcel": "Standard 9", "carrier": "Standard", "hours": 40 },
{ "parcel": "Standard 10", "carrier": "Standard", "hours": 28.5 },
{ "parcel": "Standard 11", "carrier": "Standard", "hours": 36 },
{ "parcel": "Standard 12", "carrier": "Standard", "hours": 24.5 },
{ "parcel": "Standard 13", "carrier": "Standard", "hours": 30 },
{ "parcel": "Standard 14", "carrier": "Standard", "hours": 37.5 },
{ "parcel": "Standard 15", "carrier": "Standard", "hours": 26 },
{ "parcel": "Standard 16", "carrier": "Standard", "hours": 33.5 },
{ "parcel": "Standard 17", "carrier": "Standard", "hours": 39 },
{ "parcel": "Standard 18", "carrier": "Standard", "hours": 27.5 },
{ "parcel": "Standard 19", "carrier": "Standard", "hours": 35 },
{ "parcel": "Standard 20", "carrier": "Standard", "hours": 23.5 },
{ "parcel": "Standard 21", "carrier": "Standard", "hours": 29 },
{ "parcel": "Standard 22", "carrier": "Standard", "hours": 36.5 },
{ "parcel": "Standard 23", "carrier": "Standard", "hours": 25 },
{ "parcel": "Standard 24", "carrier": "Standard", "hours": 32.5 },
{ "parcel": "Economy 1", "carrier": "Economy", "hours": 36 },
{ "parcel": "Economy 2", "carrier": "Economy", "hours": 43.5 },
{ "parcel": "Economy 3", "carrier": "Economy", "hours": 51 },
{ "parcel": "Economy 4", "carrier": "Economy", "hours": 39.5 },
{ "parcel": "Economy 5", "carrier": "Economy", "hours": 45 },
{ "parcel": "Economy 6", "carrier": "Economy", "hours": 52.5 },
{ "parcel": "Economy 7", "carrier": "Economy", "hours": 41 },
{ "parcel": "Economy 8", "carrier": "Economy", "hours": 48.5 },
{ "parcel": "Economy 9", "carrier": "Economy", "hours": 54 },
{ "parcel": "Economy 10", "carrier": "Economy", "hours": 42.5 },
{ "parcel": "Economy 11", "carrier": "Economy", "hours": 50 },
{ "parcel": "Economy 12", "carrier": "Economy", "hours": 38.5 },
{ "parcel": "Economy 13", "carrier": "Economy", "hours": 44 },
{ "parcel": "Economy 14", "carrier": "Economy", "hours": 51.5 },
{ "parcel": "Economy 15", "carrier": "Economy", "hours": 40 },
{ "parcel": "Economy 16", "carrier": "Economy", "hours": 47.5 },
{ "parcel": "Economy 17", "carrier": "Economy", "hours": 53 },
{ "parcel": "Economy 18", "carrier": "Economy", "hours": 41.5 },
{ "parcel": "Economy 19", "carrier": "Economy", "hours": 49 },
{ "parcel": "Economy 20", "carrier": "Economy", "hours": 37.5 },
{ "parcel": "Economy 21", "carrier": "Economy", "hours": 43 },
{ "parcel": "Economy 22", "carrier": "Economy", "hours": 50.5 },
{ "parcel": "Economy 23", "carrier": "Economy", "hours": 39 },
{ "parcel": "Economy 24", "carrier": "Economy", "hours": 46.5 },
] },
{ "id": "previous", "label": "Last period", "data": [
{ "parcel": "Express 1", "carrier": "Express", "hours": 7 },
{ "parcel": "Express 2", "carrier": "Express", "hours": 13.3 },
{ "parcel": "Express 3", "carrier": "Express", "hours": 20 },
{ "parcel": "Express 4", "carrier": "Express", "hours": 9.9 },
{ "parcel": "Express 5", "carrier": "Express", "hours": 15 },
{ "parcel": "Express 6", "carrier": "Express", "hours": 21.1 },
{ "parcel": "Express 7", "carrier": "Express", "hours": 11 },
{ "parcel": "Express 8", "carrier": "Express", "hours": 17.6 },
{ "parcel": "Express 9", "carrier": "Express", "hours": 22 },
{ "parcel": "Express 10", "carrier": "Express", "hours": 12.5 },
{ "parcel": "Express 11", "carrier": "Express", "hours": 19 },
{ "parcel": "Express 12", "carrier": "Express", "hours": 9 },
{ "parcel": "Express 13", "carrier": "Express", "hours": 14 },
{ "parcel": "Express 14", "carrier": "Express", "hours": 20.2 },
{ "parcel": "Express 15", "carrier": "Express", "hours": 10 },
{ "parcel": "Express 16", "carrier": "Express", "hours": 16.8 },
{ "parcel": "Express 17", "carrier": "Express", "hours": 22 },
{ "parcel": "Express 18", "carrier": "Express", "hours": 11.6 },
{ "parcel": "Express 19", "carrier": "Express", "hours": 18 },
{ "parcel": "Express 20", "carrier": "Express", "hours": 8.2 },
{ "parcel": "Express 21", "carrier": "Express", "hours": 13 },
{ "parcel": "Express 22", "carrier": "Express", "hours": 19.4 },
{ "parcel": "Express 23", "carrier": "Express", "hours": 9 },
{ "parcel": "Express 24", "carrier": "Express", "hours": 15.9 },
{ "parcel": "Standard 1", "carrier": "Standard", "hours": 19 },
{ "parcel": "Standard 2", "carrier": "Standard", "hours": 25.4 },
{ "parcel": "Standard 3", "carrier": "Standard", "hours": 32 },
{ "parcel": "Standard 4", "carrier": "Standard", "hours": 21.9 },
{ "parcel": "Standard 5", "carrier": "Standard", "hours": 27 },
{ "parcel": "Standard 6", "carrier": "Standard", "hours": 33.1 },
{ "parcel": "Standard 7", "carrier": "Standard", "hours": 23 },
{ "parcel": "Standard 8", "carrier": "Standard", "hours": 29.7 },
{ "parcel": "Standard 9", "carrier": "Standard", "hours": 34 },
{ "parcel": "Standard 10", "carrier": "Standard", "hours": 24.5 },
{ "parcel": "Standard 11", "carrier": "Standard", "hours": 31 },
{ "parcel": "Standard 12", "carrier": "Standard", "hours": 21.1 },
{ "parcel": "Standard 13", "carrier": "Standard", "hours": 26 },
{ "parcel": "Standard 14", "carrier": "Standard", "hours": 32.3 },
{ "parcel": "Standard 15", "carrier": "Standard", "hours": 22 },
{ "parcel": "Standard 16", "carrier": "Standard", "hours": 28.8 },
{ "parcel": "Standard 17", "carrier": "Standard", "hours": 34 },
{ "parcel": "Standard 18", "carrier": "Standard", "hours": 23.6 },
{ "parcel": "Standard 19", "carrier": "Standard", "hours": 30 },
{ "parcel": "Standard 20", "carrier": "Standard", "hours": 20.2 },
{ "parcel": "Standard 21", "carrier": "Standard", "hours": 25 },
{ "parcel": "Standard 22", "carrier": "Standard", "hours": 31.4 },
{ "parcel": "Standard 23", "carrier": "Standard", "hours": 22 },
{ "parcel": "Standard 24", "carrier": "Standard", "hours": 27.9 },
{ "parcel": "Economy 1", "carrier": "Economy", "hours": 31 },
{ "parcel": "Economy 2", "carrier": "Economy", "hours": 37.4 },
{ "parcel": "Economy 3", "carrier": "Economy", "hours": 44 },
{ "parcel": "Economy 4", "carrier": "Economy", "hours": 34 },
{ "parcel": "Economy 5", "carrier": "Economy", "hours": 39 },
{ "parcel": "Economy 6", "carrier": "Economy", "hours": 45.1 },
{ "parcel": "Economy 7", "carrier": "Economy", "hours": 35 },
{ "parcel": "Economy 8", "carrier": "Economy", "hours": 41.7 },
{ "parcel": "Economy 9", "carrier": "Economy", "hours": 46 },
{ "parcel": "Economy 10", "carrier": "Economy", "hours": 36.5 },
{ "parcel": "Economy 11", "carrier": "Economy", "hours": 43 },
{ "parcel": "Economy 12", "carrier": "Economy", "hours": 33.1 },
{ "parcel": "Economy 13", "carrier": "Economy", "hours": 38 },
{ "parcel": "Economy 14", "carrier": "Economy", "hours": 44.3 },
{ "parcel": "Economy 15", "carrier": "Economy", "hours": 34 },
{ "parcel": "Economy 16", "carrier": "Economy", "hours": 40.9 },
{ "parcel": "Economy 17", "carrier": "Economy", "hours": 46 },
{ "parcel": "Economy 18", "carrier": "Economy", "hours": 35.7 },
{ "parcel": "Economy 19", "carrier": "Economy", "hours": 42 },
{ "parcel": "Economy 20", "carrier": "Economy", "hours": 32.3 },
{ "parcel": "Economy 21", "carrier": "Economy", "hours": 37 },
{ "parcel": "Economy 22", "carrier": "Economy", "hours": 43.4 },
{ "parcel": "Economy 23", "carrier": "Economy", "hours": 34 },
{ "parcel": "Economy 24", "carrier": "Economy", "hours": 40 },
] },
];
export function Example() {
return (
);
}
```
#### Bubbles
`size` scales each point by area. Reach is read alongside spend and sign-ups when a point is focused, and in the table for screen readers.
```tsx
'use client';
import { ScatterChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This quarter", "data": [
{ "campaign": "Brand search", "channel": "Search", "spend": 4200, "signups": 610, "reach": 18000 },
{ "campaign": "Competitor terms", "channel": "Search", "spend": 9800, "signups": 720, "reach": 22000 },
{ "campaign": "Product search", "channel": "Search", "spend": 14500, "signups": 1380, "reach": 31000 },
{ "campaign": "Shopping ads", "channel": "Search", "spend": 21000, "signups": 1690, "reach": 42000 },
{ "campaign": "Generic terms", "channel": "Search", "spend": 27500, "signups": 1540, "reach": 50000 },
{ "campaign": "Launch video", "channel": "Social", "spend": 6400, "signups": 290, "reach": 64000 },
{ "campaign": "Creator series", "channel": "Social", "spend": 12800, "signups": 820, "reach": 71000 },
{ "campaign": "Carousel ads", "channel": "Social", "spend": 18200, "signups": 760, "reach": 48000 },
{ "campaign": "Story ads", "channel": "Social", "spend": 24600, "signups": 1120, "reach": 83000 },
{ "campaign": "Lookalike audiences", "channel": "Social", "spend": 33800, "signups": 1470, "reach": 96000 },
{ "campaign": "Welcome series", "channel": "Email", "spend": 1800, "signups": 540, "reach": 9000 },
{ "campaign": "Newsletter feature", "channel": "Email", "spend": 3100, "signups": 460, "reach": 14000 },
{ "campaign": "Win-back", "channel": "Email", "spend": 5200, "signups": 830, "reach": 12000 },
{ "campaign": "Partner list", "channel": "Email", "spend": 8600, "signups": 690, "reach": 21000 },
] },
{ "id": "previous", "label": "Last quarter", "data": [
{ "campaign": "Brand search", "channel": "Search", "spend": 4200, "signups": 525, "reach": 15480 },
{ "campaign": "Competitor terms", "channel": "Search", "spend": 9800, "signups": 619, "reach": 18920 },
{ "campaign": "Product search", "channel": "Search", "spend": 14500, "signups": 1187, "reach": 26660 },
{ "campaign": "Shopping ads", "channel": "Search", "spend": 21000, "signups": 1453, "reach": 36120 },
{ "campaign": "Generic terms", "channel": "Search", "spend": 27500, "signups": 1324, "reach": 43000 },
{ "campaign": "Launch video", "channel": "Social", "spend": 6400, "signups": 249, "reach": 55040 },
{ "campaign": "Creator series", "channel": "Social", "spend": 12800, "signups": 705, "reach": 61060 },
{ "campaign": "Carousel ads", "channel": "Social", "spend": 18200, "signups": 654, "reach": 41280 },
{ "campaign": "Story ads", "channel": "Social", "spend": 24600, "signups": 963, "reach": 71380 },
{ "campaign": "Lookalike audiences", "channel": "Social", "spend": 33800, "signups": 1264, "reach": 82560 },
{ "campaign": "Welcome series", "channel": "Email", "spend": 1800, "signups": 464, "reach": 7740 },
{ "campaign": "Newsletter feature", "channel": "Email", "spend": 3100, "signups": 396, "reach": 12040 },
{ "campaign": "Win-back", "channel": "Email", "spend": 5200, "signups": 714, "reach": 10320 },
{ "campaign": "Partner list", "channel": "Email", "spend": 8600, "signups": 593, "reach": 18060 },
] },
];
export function Example() {
return (
);
}
```
#### Groups
`group` colors each channel and adds a legend with its sign-ups. Hover a channel to pick its points out; click to hold it.
```tsx
'use client';
import { ScatterChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This quarter", "data": [
{ "campaign": "Brand search", "channel": "Search", "spend": 4200, "signups": 610, "reach": 18000 },
{ "campaign": "Competitor terms", "channel": "Search", "spend": 9800, "signups": 720, "reach": 22000 },
{ "campaign": "Product search", "channel": "Search", "spend": 14500, "signups": 1380, "reach": 31000 },
{ "campaign": "Shopping ads", "channel": "Search", "spend": 21000, "signups": 1690, "reach": 42000 },
{ "campaign": "Generic terms", "channel": "Search", "spend": 27500, "signups": 1540, "reach": 50000 },
{ "campaign": "Launch video", "channel": "Social", "spend": 6400, "signups": 290, "reach": 64000 },
{ "campaign": "Creator series", "channel": "Social", "spend": 12800, "signups": 820, "reach": 71000 },
{ "campaign": "Carousel ads", "channel": "Social", "spend": 18200, "signups": 760, "reach": 48000 },
{ "campaign": "Story ads", "channel": "Social", "spend": 24600, "signups": 1120, "reach": 83000 },
{ "campaign": "Lookalike audiences", "channel": "Social", "spend": 33800, "signups": 1470, "reach": 96000 },
{ "campaign": "Welcome series", "channel": "Email", "spend": 1800, "signups": 540, "reach": 9000 },
{ "campaign": "Newsletter feature", "channel": "Email", "spend": 3100, "signups": 460, "reach": 14000 },
{ "campaign": "Win-back", "channel": "Email", "spend": 5200, "signups": 830, "reach": 12000 },
{ "campaign": "Partner list", "channel": "Email", "spend": 8600, "signups": 690, "reach": 21000 },
], "delta": 0.198 },
{ "id": "previous", "label": "Last quarter", "data": [
{ "campaign": "Brand search", "channel": "Search", "spend": 4200, "signups": 525, "reach": 15480 },
{ "campaign": "Competitor terms", "channel": "Search", "spend": 9800, "signups": 619, "reach": 18920 },
{ "campaign": "Product search", "channel": "Search", "spend": 14500, "signups": 1187, "reach": 26660 },
{ "campaign": "Shopping ads", "channel": "Search", "spend": 21000, "signups": 1453, "reach": 36120 },
{ "campaign": "Generic terms", "channel": "Search", "spend": 27500, "signups": 1324, "reach": 43000 },
{ "campaign": "Launch video", "channel": "Social", "spend": 6400, "signups": 249, "reach": 55040 },
{ "campaign": "Creator series", "channel": "Social", "spend": 12800, "signups": 705, "reach": 61060 },
{ "campaign": "Carousel ads", "channel": "Social", "spend": 18200, "signups": 654, "reach": 41280 },
{ "campaign": "Story ads", "channel": "Social", "spend": 24600, "signups": 963, "reach": 71380 },
{ "campaign": "Lookalike audiences", "channel": "Social", "spend": 33800, "signups": 1264, "reach": 82560 },
{ "campaign": "Welcome series", "channel": "Email", "spend": 1800, "signups": 464, "reach": 7740 },
{ "campaign": "Newsletter feature", "channel": "Email", "spend": 3100, "signups": 396, "reach": 12040 },
{ "campaign": "Win-back", "channel": "Email", "spend": 5200, "signups": 714, "reach": 10320 },
{ "campaign": "Partner list", "channel": "Email", "spend": 8600, "signups": 593, "reach": 18060 },
], "delta": 0.089 },
];
export function Example() {
return (
);
}
```
#### Points without a value
Two campaigns are still attributing sign-ups. They are left off the plot rather than drawn at zero, and the footer says how many are missing.
```tsx
'use client';
import { ScatterChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This quarter", "data": [
{ "campaign": "Brand search", "channel": "Search", "spend": 4200, "signups": 610, "reach": 18000 },
{ "campaign": "Competitor terms", "channel": "Search", "spend": 9800, "signups": 720, "reach": 22000 },
{ "campaign": "Product search", "channel": "Search", "spend": 14500, "signups": 1380, "reach": 31000 },
{ "campaign": "Shopping ads", "channel": "Search", "spend": 21000, "signups": 1690, "reach": 42000 },
{ "campaign": "Generic terms", "channel": "Search", "spend": 27500, "signups": 1540, "reach": 50000 },
{ "campaign": "Launch video", "channel": "Social", "spend": 6400, "signups": 290, "reach": 64000 },
{ "campaign": "Creator series", "channel": "Social", "spend": 12800, "signups": 820, "reach": 71000 },
{ "campaign": "Carousel ads", "channel": "Social", "spend": 18200, "signups": 760, "reach": 48000 },
{ "campaign": "Story ads", "channel": "Social", "spend": 24600, "signups": null, "reach": 83000 },
{ "campaign": "Lookalike audiences", "channel": "Social", "spend": 33800, "signups": 1470, "reach": 96000 },
{ "campaign": "Welcome series", "channel": "Email", "spend": 1800, "signups": 540, "reach": 9000 },
{ "campaign": "Newsletter feature", "channel": "Email", "spend": 3100, "signups": 460, "reach": 14000 },
{ "campaign": "Win-back", "channel": "Email", "spend": 5200, "signups": 830, "reach": 12000 },
{ "campaign": "Partner list", "channel": "Email", "spend": 8600, "signups": null, "reach": 21000 },
] },
{ "id": "previous", "label": "Last quarter", "data": [
{ "campaign": "Brand search", "channel": "Search", "spend": 4200, "signups": 525, "reach": 15480 },
{ "campaign": "Competitor terms", "channel": "Search", "spend": 9800, "signups": 619, "reach": 18920 },
{ "campaign": "Product search", "channel": "Search", "spend": 14500, "signups": 1187, "reach": 26660 },
{ "campaign": "Shopping ads", "channel": "Search", "spend": 21000, "signups": 1453, "reach": 36120 },
{ "campaign": "Generic terms", "channel": "Search", "spend": 27500, "signups": 1324, "reach": 43000 },
{ "campaign": "Launch video", "channel": "Social", "spend": 6400, "signups": 249, "reach": 55040 },
{ "campaign": "Creator series", "channel": "Social", "spend": 12800, "signups": 705, "reach": 61060 },
{ "campaign": "Carousel ads", "channel": "Social", "spend": 18200, "signups": 654, "reach": 41280 },
{ "campaign": "Story ads", "channel": "Social", "spend": 24600, "signups": null, "reach": 71380 },
{ "campaign": "Lookalike audiences", "channel": "Social", "spend": 33800, "signups": 1264, "reach": 82560 },
{ "campaign": "Welcome series", "channel": "Email", "spend": 1800, "signups": 464, "reach": 7740 },
{ "campaign": "Newsletter feature", "channel": "Email", "spend": 3100, "signups": 396, "reach": 12040 },
{ "campaign": "Win-back", "channel": "Email", "spend": 5200, "signups": 714, "reach": 10320 },
{ "campaign": "Partner list", "channel": "Email", "spend": 8600, "signups": null, "reach": 18060 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per point.
const campaignResults = [
{ campaign: 'Brand search', channel: 'Search', spend: 4200, signups: 610, reach: 18000 },
{ campaign: 'Story ads', channel: 'Social', spend: 24600, signups: null, reach: 83000 },
// …
];
```
Each row is one point: `x` places it across, `y` places it up and feeds the headline, and TypeScript rejects anything but numeric fields for both. `label` names a point when it is read; `size` scales bubbles by area, so a point twice the value covers twice the ink; `group` colors points and adds a legend. A row missing `x` or `y` can’t be placed, so it is left off the plot, counted in the footer, and still listed for screen readers. Axes start at zero when the data starts near it, and at a round number otherwise.
### Period select
```tsx
```
### Hover
Hovering near a point reads it in the headline and names it beside the number, “Product search · Spend $14,500”, with dashed guides and pills marking its value on both axes. Click to pin a point. The plot is one tab stop: arrow keys step through points from left to right, Home and End jump to either end, Enter pins, and Escape lets go. Hovering a legend item reads that group. Points pop in from left to right on first view and glide to their new place when the period changes.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `trails` (`boolean`): Join successive observations within each group. Gaps break trails; duplicate or missing time keys suppress that group’s trail.
- `trailOrder` (`numeric key of Row`): Explicit numeric time order. Otherwise follows input row order.
- `data` (`Row[]`): One row per point. Omit when using ranges.
- `x` (`numeric key of Row`): Places each point across.
- `y` (`numeric key of Row`): Places each point up, and drives the headline.
- `label` (`text key of Row`): Names a point when it is read. Unique labels also keep points steady across periods.
- `size` (`numeric key of Row`): Sizes points by area, turning dots into bubbles.
- `sizeLabel` (`string`): Names the size measure, e.g. “Reach”.
- `group` (`text key of Row`): Colors points by group and adds a legend with each group’s value.
- `xLabel` (`string`): Title for the horizontal axis.
- `yLabel` (`string`): Title for the vertical axis.
- `xFormat` (`Intl.NumberFormatOptions`): Formats x values and ticks, e.g. currency or seconds.
- `trend` (`boolean`): A least-squares line through the points, with its r² in the footer.
- `aggregate` (`'sum' | 'mean' | 'max'`): How the resting headline sums up every plotted y. Sum by default.
- `height` (`number`): Plot height in pixels, including the axes. Defaults to 260.
- `headline` (`number`): Resting headline. Defaults to the aggregate of every plotted y.
- `delta` (`number`): Fractional change for the chip.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label in the header.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the points.
- `color` (`string`): Any CSS color for points without a group.
- `depth` (`boolean`): Draws each point as a lit sphere with a soft contact shadow. Centers and sizes stay exact.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): False removes the legend without changing the data. How the group legend lays out: value tiles (default), a compact inline key, list rows, tinted pills, or bars against the largest.
- `legendSwatch` (`'square' | 'dot' | 'line'`): The mark beside each legend label. Defaults to a rounded square.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `formatX` (`(value: string | number | Date) => string`): Custom x label text.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
### Strip and beeswarm: StripChartCard
StripChartCard shows individual measurements within categories, with mean as the default headline. Strip uses stable vertical jitter; beeswarm prevents collisions and expands the plot when needed. Both preserve each numeric position. Missing values are counted and remain in the accessible table. Unique labels preserve pin identity across updates.
```tsx
import { StripChartCard } from '@lilt-ui/charts';
```
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 260. Dense lanes expand to keep every mark visible.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `category` (`text key of Row`): Category lane for each point.
- `value` (`numeric key of Row`): Measured horizontal position.
- `label` (`text key of Row`): Unique accessible point name; falls back to row index.
- `display` (`'strip' | 'beeswarm'`): Stable jitter (default) or collision-free placement.
- `radius` (`number`): Point radius in pixels, 2–12; default 4.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Radar chart: `RadarChartCard`
Compare strengths across several dimensions. Docs: https://liltui.vercel.app/charts/radar
```tsx
import { RadarChartCard } from '@lilt-ui/charts';
```
### Complete examples
#### Radar chart card
```tsx
'use client';
import { RadarChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "quarter", "label": "This quarter", "data": [
{ "area": "Quality", "current": 82, "target": 92 },
{ "area": "Test coverage", "current": 74, "target": 90 },
{ "area": "Accessibility", "current": 88, "target": 90 },
{ "area": "Reliability", "current": 91, "target": 95 },
{ "area": "Performance", "current": 69, "target": 85 },
{ "area": "Documentation", "current": 63, "target": 80 },
], "delta": 0.086 },
{ "id": "last-quarter", "label": "Last quarter", "data": [
{ "area": "Quality", "current": 76, "target": 92 },
{ "area": "Test coverage", "current": 65, "target": 90 },
{ "area": "Accessibility", "current": 86, "target": 90 },
{ "area": "Reliability", "current": 87, "target": 95 },
{ "area": "Performance", "current": 58, "target": 85 },
{ "area": "Documentation", "current": 58, "target": 80 },
], "delta": 0.031 },
];
export function Example() {
return (
);
}
```
#### One profile
A single series: the filled shape shows where the release is strong and where it lags.
```tsx
'use client';
import { RadarChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This quarter", "data": [
{ "area": "Quality", "current": 82, "target": 92 },
{ "area": "Test coverage", "current": 74, "target": 90 },
{ "area": "Accessibility", "current": 88, "target": 90 },
{ "area": "Reliability", "current": 91, "target": 95 },
{ "area": "Performance", "current": 69, "target": 85 },
{ "area": "Documentation", "current": 63, "target": 80 },
] },
{ "id": "previous", "label": "Last quarter", "data": [
{ "area": "Quality", "current": 71, "target": 79 },
{ "area": "Test coverage", "current": 64, "target": 77 },
{ "area": "Accessibility", "current": 76, "target": 77 },
{ "area": "Reliability", "current": 78, "target": 82 },
{ "area": "Performance", "current": 59, "target": 73 },
{ "area": "Documentation", "current": 54, "target": 69 },
] },
];
export function Example() {
return (
);
}
```
#### Comparing profiles
Three products on one ten-point scale. `domain` fixes the scale at 0 to 10, and hovering a legend item picks out one product.
```tsx
'use client';
import { RadarChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This quarter", "data": [
{ "criterion": "Speed", "lilt": 9, "northwind": 6, "contoso": 7 },
{ "criterion": "Price", "lilt": 7, "northwind": 8, "contoso": 5 },
{ "criterion": "Support", "lilt": 8, "northwind": 5, "contoso": 9 },
{ "criterion": "Features", "lilt": 7, "northwind": 9, "contoso": 6 },
{ "criterion": "Integrations", "lilt": 6, "northwind": 7, "contoso": 8 },
{ "criterion": "Security", "lilt": 9, "northwind": 7, "contoso": 8 },
] },
{ "id": "previous", "label": "Last quarter", "data": [
{ "criterion": "Speed", "lilt": 8, "northwind": 5, "contoso": 6 },
{ "criterion": "Price", "lilt": 6, "northwind": 7, "contoso": 4 },
{ "criterion": "Support", "lilt": 7, "northwind": 4, "contoso": 8 },
{ "criterion": "Features", "lilt": 6, "northwind": 8, "contoso": 5 },
{ "criterion": "Integrations", "lilt": 5, "northwind": 6, "contoso": 7 },
{ "criterion": "Security", "lilt": 8, "northwind": 6, "contoso": 7 },
] },
];
export function Example() {
return (
);
}
```
#### A dimension with no data
Accessibility wasn’t audited this quarter. The outline breaks at that spoke, the fill drops, the label says so, and the average counts only what was measured.
```tsx
'use client';
import { RadarChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This quarter", "data": [
{ "area": "Quality", "current": 82, "target": 92 },
{ "area": "Test coverage", "current": 74, "target": 90 },
{ "area": "Accessibility", "current": null, "target": 90 },
{ "area": "Reliability", "current": 91, "target": 95 },
{ "area": "Performance", "current": 69, "target": 85 },
{ "area": "Documentation", "current": 63, "target": 80 },
] },
{ "id": "previous", "label": "Last quarter", "data": [
{ "area": "Quality", "current": 71, "target": 79 },
{ "area": "Test coverage", "current": 64, "target": 77 },
{ "area": "Accessibility", "current": null, "target": 77 },
{ "area": "Reliability", "current": 78, "target": 82 },
{ "area": "Performance", "current": 59, "target": 73 },
{ "area": "Documentation", "current": 54, "target": 69 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per dimension, drawn clockwise from the top.
const releaseReadiness = [
{ area: 'Quality', current: 82, target: 92 },
{ area: 'Accessibility', current: null, target: 90 }, // not audited
// …
];
```
Each row is one dimension, drawn clockwise from the top in the order given; `category` names it, and each series is a numeric field of the row, checked by TypeScript. A radar needs three to twelve dimensions on one shared scale: `domain` sets it, and by default it runs from zero to a round number above the highest value. The headline is the average of the first solid series; dashed series, such as a target, draw as an outline and stay out of it. A missing value breaks the outline at that spoke and drops the fill, so a gap never looks like a low score.
### Period select
```tsx
```
### Hover
Hovering near a spoke reads that dimension in the headline, with every other series beside it: “Performance · Target 85”. The spoke and label darken, the vertices on it fill, and the legend switches from averages to that dimension’s values. Hovering a legend item picks out its profile. The plot is one tab stop: arrow keys step around the spokes, Enter pins, and Escape lets go. Profiles grow from the center on first view and when the period changes.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per dimension, clockwise from the top. Omit when using ranges.
- `category` (`text key of Row`): Names each dimension. Must be unique.
- `series` (`{ key, label?, color?, dashed? }[]`): Profiles to compare, one numeric field each. Dashed series draw as an outline and stay out of the headline.
- `domain` (`[number, number]`): Values at the center and the outer ring. Defaults to zero through a round maximum.
- `aggregate` (`'mean' | 'sum' | 'max'`): How the resting headline sums up the first series. Mean by default.
- `grid` (`'polygon' | 'circle'`): Rings that follow the spokes (default), or round rings.
- `height` (`number`): Plot height in pixels. Defaults to 300.
- `headline` (`number`): Resting headline. Defaults to the aggregate of the first series.
- `delta` (`number`): Fractional change for the chip.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label in the header.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the dimensions.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): False removes the legend without changing the data. How the series legend lays out: value tiles (default), a compact inline key, list rows, tinted pills, or bars against the largest.
- `legendSwatch` (`'square' | 'dot' | 'line'`): The mark beside each legend label. Defaults to a rounded square.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
## Box plot: `BoxPlotCard`
Distributions side by side: quartiles, median, whiskers and outliers from raw samples. Docs: https://liltui.vercel.app/charts/box-plot
```tsx
import { BoxPlotCard } from '@lilt-ui/charts';
```
### Complete examples
#### Box plot card
```tsx
'use client';
import { BoxPlotCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const regionLatency = [
{ "region": "US East", "samples": [
43,
35,
37,
51,
57,
45,
51,
50,
26,
50,
40,
30,
26,
25,
37,
48,
50,
53,
53,
48,
61,
39,
43,
41,
28,
43,
31,
38,
42,
51,
34,
50,
43,
33,
36,
59,
46,
37,
41,
38,
45,
55,
37,
34,
32,
47,
52,
36,
50,
50,
28,
33,
55,
60,
45,
33,
38,
51,
38,
33,
32,
39,
53,
51,
44,
42,
40,
36,
58,
41,
43,
50,
37,
32,
48,
34,
38,
68,
31,
51,
39,
38,
35,
50,
31,
27,
34,
47,
34,
37,
50,
38,
84,
41,
37,
47,
48,
49,
35,
24,
30,
45,
31,
52,
50,
37,
47,
32,
40,
29,
29,
30,
32,
50,
29,
34,
37,
47,
33,
37,
] },
{ "region": "US West", "samples": [
41,
56,
47,
51,
55,
59,
50,
51,
37,
32,
55,
37,
48,
56,
46,
65,
57,
49,
59,
32,
38,
46,
47,
50,
43,
51,
62,
48,
45,
56,
42,
38,
41,
48,
45,
56,
41,
58,
46,
63,
36,
44,
43,
53,
82,
61,
39,
41,
43,
61,
54,
49,
52,
33,
50,
35,
61,
55,
50,
49,
63,
67,
43,
53,
49,
50,
49,
31,
41,
53,
48,
35,
42,
52,
33,
43,
62,
38,
56,
39,
51,
62,
49,
37,
58,
57,
33,
60,
52,
46,
44,
49,
51,
47,
52,
44,
70,
54,
62,
53,
74,
61,
41,
86,
39,
33,
47,
84,
54,
50,
41,
86,
45,
54,
45,
35,
50,
46,
40,
38,
] },
{ "region": "Europe", "samples": [
89,
89,
68,
83,
69,
103,
41,
85,
51,
54,
56,
50,
72,
99,
84,
46,
63,
77,
89,
58,
58,
74,
64,
74,
77,
60,
47,
47,
60,
57,
46,
53,
59,
88,
79,
51,
49,
46,
61,
67,
79,
37,
56,
79,
71,
72,
62,
86,
54,
58,
46,
72,
54,
69,
71,
61,
60,
57,
52,
74,
52,
52,
95,
76,
60,
80,
50,
48,
72,
76,
58,
58,
111,
66,
73,
40,
88,
74,
40,
47,
63,
66,
77,
54,
57,
76,
48,
74,
65,
41,
84,
55,
63,
72,
80,
75,
66,
55,
69,
79,
57,
72,
54,
103,
58,
57,
66,
56,
70,
62,
64,
64,
62,
49,
53,
66,
70,
61,
51,
47,
] },
{ "region": "Asia Pacific", "samples": [
99,
99,
136,
82,
155,
91,
79,
126,
136,
68,
123,
106,
93,
97,
124,
101,
83,
111,
112,
56,
132,
101,
99,
168,
127,
113,
158,
114,
138,
56,
166,
119,
84,
70,
103,
85,
86,
85,
91,
67,
84,
115,
160,
59,
121,
150,
102,
91,
104,
142,
65,
70,
121,
144,
154,
130,
109,
172,
63,
71,
68,
120,
133,
57,
107,
78,
85,
60,
100,
126,
191,
101,
123,
85,
148,
144,
89,
84,
100,
137,
168,
87,
68,
118,
98,
102,
201,
117,
140,
97,
87,
122,
73,
72,
116,
140,
135,
100,
111,
99,
91,
139,
94,
137,
108,
63,
84,
159,
66,
103,
81,
67,
92,
117,
135,
123,
69,
92,
138,
112,
] },
{ "region": "South America", "samples": [
98,
118,
108,
134,
114,
105,
103,
132,
132,
131,
116,
70,
127,
81,
127,
92,
190,
125,
141,
121,
179,
145,
104,
133,
98,
91,
153,
114,
85,
112,
90,
125,
117,
102,
116,
127,
193,
81,
119,
139,
165,
238,
117,
107,
151,
108,
196,
160,
105,
99,
139,
109,
74,
74,
135,
93,
111,
146,
176,
149,
95,
93,
141,
106,
93,
180,
87,
116,
116,
101,
66,
128,
124,
108,
85,
96,
103,
73,
125,
121,
103,
151,
97,
101,
86,
117,
152,
182,
130,
98,
97,
137,
171,
109,
128,
104,
95,
119,
135,
181,
123,
189,
114,
86,
130,
140,
81,
124,
179,
92,
101,
94,
125,
126,
109,
124,
162,
79,
87,
96,
] },
];
export function Example() {
return (
);
}
```
#### Delivery distributions
A density silhouette reveals each delivery distribution, with measured sample dots and a median readout. Deterministic horizontal offsets separate samples without changing their values.
```tsx
'use client';
import { ViolinCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const deliverySamples = [
{ "parcel": "Standard 1", "carrier": "Standard", "hours": 40 },
{ "parcel": "Standard 2", "carrier": "Standard", "hours": 50 },
{ "parcel": "Standard 3", "carrier": "Standard", "hours": 31 },
{ "parcel": "Standard 4", "carrier": "Standard", "hours": 55 },
{ "parcel": "Standard 5", "carrier": "Standard", "hours": 45 },
{ "parcel": "Standard 6", "carrier": "Standard", "hours": 34 },
{ "parcel": "Standard 7", "carrier": "Standard", "hours": 53 },
{ "parcel": "Standard 8", "carrier": "Standard", "hours": 33 },
{ "parcel": "Standard 9", "carrier": "Standard", "hours": 49 },
{ "parcel": "Standard 10", "carrier": "Standard", "hours": 51 },
{ "parcel": "Standard 11", "carrier": "Standard", "hours": 29 },
{ "parcel": "Standard 12", "carrier": "Standard", "hours": 53 },
{ "parcel": "Standard 13", "carrier": "Standard", "hours": 38 },
{ "parcel": "Standard 14", "carrier": "Standard", "hours": 42 },
{ "parcel": "Standard 15", "carrier": "Standard", "hours": 57 },
{ "parcel": "Standard 16", "carrier": "Standard", "hours": 28 },
{ "parcel": "Standard 17", "carrier": "Standard", "hours": 49 },
{ "parcel": "Standard 18", "carrier": "Standard", "hours": 44 },
{ "parcel": "Standard 19", "carrier": "Standard", "hours": 36 },
{ "parcel": "Standard 20", "carrier": "Standard", "hours": 59 },
{ "parcel": "Standard 21", "carrier": "Standard", "hours": 31 },
{ "parcel": "Standard 22", "carrier": "Standard", "hours": 43 },
{ "parcel": "Standard 23", "carrier": "Standard", "hours": 50 },
{ "parcel": "Standard 24", "carrier": "Standard", "hours": 33 },
{ "parcel": "Standard 25", "carrier": "Standard", "hours": 57 },
{ "parcel": "Standard 26", "carrier": "Standard", "hours": 37 },
{ "parcel": "Standard 27", "carrier": "Standard", "hours": 36 },
{ "parcel": "Standard 28", "carrier": "Standard", "hours": 55 },
{ "parcel": "Express 1", "carrier": "Express", "hours": 22 },
{ "parcel": "Express 2", "carrier": "Express", "hours": 27 },
{ "parcel": "Express 3", "carrier": "Express", "hours": 20 },
{ "parcel": "Express 4", "carrier": "Express", "hours": 31 },
{ "parcel": "Express 5", "carrier": "Express", "hours": 28 },
{ "parcel": "Express 6", "carrier": "Express", "hours": 19 },
{ "parcel": "Express 7", "carrier": "Express", "hours": 29 },
{ "parcel": "Express 8", "carrier": "Express", "hours": 21 },
{ "parcel": "Express 9", "carrier": "Express", "hours": 29 },
{ "parcel": "Express 10", "carrier": "Express", "hours": 31 },
{ "parcel": "Express 11", "carrier": "Express", "hours": 17 },
{ "parcel": "Express 12", "carrier": "Express", "hours": 28 },
{ "parcel": "Express 13", "carrier": "Express", "hours": 23 },
{ "parcel": "Express 14", "carrier": "Express", "hours": 26 },
{ "parcel": "Express 15", "carrier": "Express", "hours": 33 },
{ "parcel": "Express 16", "carrier": "Express", "hours": 17 },
{ "parcel": "Express 17", "carrier": "Express", "hours": 27 },
{ "parcel": "Express 18", "carrier": "Express", "hours": 26 },
{ "parcel": "Express 19", "carrier": "Express", "hours": 24 },
{ "parcel": "Express 20", "carrier": "Express", "hours": 34 },
{ "parcel": "Express 21", "carrier": "Express", "hours": 18 },
{ "parcel": "Express 22", "carrier": "Express", "hours": 24 },
{ "parcel": "Express 23", "carrier": "Express", "hours": 28 },
{ "parcel": "Express 24", "carrier": "Express", "hours": 22 },
{ "parcel": "Express 25", "carrier": "Express", "hours": 33 },
{ "parcel": "Express 26", "carrier": "Express", "hours": 21 },
{ "parcel": "Express 27", "carrier": "Express", "hours": 21 },
{ "parcel": "Express 28", "carrier": "Express", "hours": 30 },
{ "parcel": "Local 1", "carrier": "Local", "hours": 12 },
{ "parcel": "Local 2", "carrier": "Local", "hours": 17 },
{ "parcel": "Local 3", "carrier": "Local", "hours": 10 },
{ "parcel": "Local 4", "carrier": "Local", "hours": 21 },
{ "parcel": "Local 5", "carrier": "Local", "hours": 18 },
{ "parcel": "Local 6", "carrier": "Local", "hours": 9 },
{ "parcel": "Local 7", "carrier": "Local", "hours": 19 },
{ "parcel": "Local 8", "carrier": "Local", "hours": 11 },
{ "parcel": "Local 9", "carrier": "Local", "hours": 19 },
{ "parcel": "Local 10", "carrier": "Local", "hours": 21 },
{ "parcel": "Local 11", "carrier": "Local", "hours": 7 },
{ "parcel": "Local 12", "carrier": "Local", "hours": 18 },
{ "parcel": "Local 13", "carrier": "Local", "hours": 13 },
{ "parcel": "Local 14", "carrier": "Local", "hours": 16 },
{ "parcel": "Local 15", "carrier": "Local", "hours": 23 },
{ "parcel": "Local 16", "carrier": "Local", "hours": 7 },
{ "parcel": "Local 17", "carrier": "Local", "hours": 17 },
{ "parcel": "Local 18", "carrier": "Local", "hours": 16 },
{ "parcel": "Local 19", "carrier": "Local", "hours": 14 },
{ "parcel": "Local 20", "carrier": "Local", "hours": 24 },
{ "parcel": "Local 21", "carrier": "Local", "hours": 8 },
{ "parcel": "Local 22", "carrier": "Local", "hours": 14 },
{ "parcel": "Local 23", "carrier": "Local", "hours": 18 },
{ "parcel": "Local 24", "carrier": "Local", "hours": 12 },
{ "parcel": "Local 25", "carrier": "Local", "hours": 23 },
{ "parcel": "Local 26", "carrier": "Local", "hours": 11 },
{ "parcel": "Local 27", "carrier": "Local", "hours": 11 },
{ "parcel": "Local 28", "carrier": "Local", "hours": 20 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per box with its raw samples; Lilt computes the statistics.
const regionLatency = [
{ region: 'US East', samples: [38, 44, 41, 52, 36] },
{ region: 'Europe', samples: [61, 58, 70, 66, 95] },
];
```
Quartiles use linear interpolation. Whiskers reach the furthest sample within 1.5 times the interquartile range, and samples beyond them draw as outliers, which the axis always includes. The headline is the median of every sample pooled, not an average of medians. `summarizeBox` returns the same statistics, and `BoxPlot` draws precomputed quartiles from any series’ `fields`.
### Hover
Hover a box to read its median in the headline with its quartiles beside it. With `hover="tooltip"`, the panel also lists the whisker ends.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `data` (`Row[]`): One row per x position. Omit when using ranges.
- `x` (`key of Row`): Text, number, or Date field for the x axis.
- `samples` (`key of Row`): Field holding each row’s raw samples, as a number array.
- `label` (`string`): Names the series in hover. Defaults to Median.
- `color` (`string`): Any CSS color.
- `outliers` (`boolean`): Draw samples beyond the whiskers as dots. Defaults to true.
- `depth` (`boolean`): Draws each box as a solid block centered on its group, with whiskers through its middle and the median wrapped around it.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `delta` (`number`): Fractional change for the chip: 0.082 shows +8.2%.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `headline` (`number`): Resting headline. Defaults to the aggregate of non-reference series; dashed series are excluded.
- `range` (`string`): Static period label in the header.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): False removes the legend without changing the data. How the legend under the plot lays out: value tiles (default), a compact inline key, list rows, tinted pills, or bars that also draw each value against the largest.
- `legendSwatch` (`'square' | 'dot' | 'line'`): The mark beside each legend label. Defaults to a rounded square.
- `height` (`number`): Plot height in pixels. Defaults to 240.
- `axis` (`'minimal' | 'dots' | 'inline' | 'ruler' | 'classic' | 'segmented' | { x, y }`): Axis preset. Minimal (default) labels only the x ends and has no grid. Set one per axis with `{ x, y }`; a segmented axis can take a `gradient` to read as a range.
- `hover` (`'pills' | 'tooltip' | 'strip' | 'headline'`): The one readout for the hovered point: pills on the axes (default), a tooltip with every series, a strip docked above the plot, or the headline and tiles alone.
- `hoverStyle` (`'soft' | 'solid' | 'accent'`): How the pills or tooltip look. Soft (default) is surface glass; accent tints it with the hovered series.
- `pillPosition` (`'auto' | 'mark' | 'axis'`): Where the value pill sits: above the hovered mark, or on the y axis. Auto picks mark when there are no y labels.
- `tooltipIndicator` (`'square' | 'dot' | 'line'`): Series marker on each tooltip row, with hover="tooltip". Square by default.
- `background` (`'dots' | 'grid' | 'lines' | 'none'`): Texture behind the marks. Dots by default, with a hover spotlight.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `axisInset` (`number`): Padding between the plot edges and axis labels or pills.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `compare` (`boolean | 'headline' | 'badge'`): Drag across the plot to compare two points in time. True or headline reads the change in the headline; badge reads it in the card’s tab and leaves the headline at rest.
- `sync` (`string`): Link hover and pins with every card that uses the same name, matched by x value. A click pins them all, with a ghost pin on the others; Alt-click pins one card only.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `formatAxisValue` (`(value: number) => string`): Custom compact axis value text.
- `formatX` (`(value: string | number | Date) => string`): Custom x label text.
- `xType` (`'category' | 'number' | 'time'`): Override inferred x type. Use time for numeric Unix timestamps in milliseconds.
- `spotlight` (`boolean`): Highlight the inspected position in the plot background. Defaults to true.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
- `pillValue` (`'series' | 'stack'`): Read an individual series value (default) or its stacked height. Has no effect when the card has no stacked series.
- `decimate` (`boolean`): Defaults to true. Line and Area marks retain at most four observations per pixel column. Other marks draw every row; inspection and summaries always read the full data.
### Violin plot: ViolinCard
A density silhouette reveals each delivery distribution, with measured sample dots and a median readout. Deterministic horizontal offsets separate samples without changing their values. All three loading styles share the skeleton exit, entrance, pointer/keyboard pinning, touch glide, reduced motion, and accessible readings table. Aggregate marks report null as their original datum.
```tsx
import { ViolinCard } from '@lilt-ui/charts';
```
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 260. Dense lanes expand to keep every mark visible.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Summarizes the group medians at rest. Defaults to mean.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Legend layout; false hides it. Correlation defaults to false.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Legend marker, square by default.
- `category` (`text key of Row`): Category for each sample.
- `value` (`numeric key of Row`): Measured sample; missing samples remain in the table.
- `label` (`text key of Row`): Optional sample name.
- `points` (`boolean`): Show every sample, default true.
- `bandwidth` (`number`): Positive kernel bandwidth in measurement units; data-derived when omitted.
- `scale` (`'width' | 'density'`): Equal maximum widths (default) or a common density scale.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Chord loom: `ChordLoomCard`
Weighted flows woven through a tilted circular frame, with every ribbon available to inspect. Docs: https://liltui.vercel.app/charts/chord-loom
```tsx
import { ChordLoomCard } from '@lilt-ui/charts';
```
### Complete examples
#### Team handoffs
```tsx
'use client';
import { ChordLoomCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const teamHandoffs = [
{ "from": "Design", "to": "Build", "count": 84 },
{ "from": "Design", "to": "Research", "count": 26 },
{ "from": "Build", "to": "Review", "count": 68 },
{ "from": "Review", "to": "Design", "count": 32 },
{ "from": "Review", "to": "Launch", "count": 46 },
{ "from": "Research", "to": "Build", "count": 38 },
{ "from": "Launch", "to": "Research", "count": 20 },
];
export function Example() {
return (
);
}
```
#### Incomplete handoffs
Missing and measured-zero routes stay in the data table without claiming a flow.
```tsx
'use client';
import { ChordLoomCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const handoffsWithGaps = [
{ "from": "Design", "to": "Build", "count": 84 },
{ "from": "Design", "to": "Research", "count": 26 },
{ "from": "Build", "to": "Review", "count": null },
{ "from": "Review", "to": "Design", "count": 32 },
{ "from": "Review", "to": "Launch", "count": 0 },
{ "from": "Research", "to": "Build", "count": 38 },
{ "from": "Launch", "to": "Research", "count": 20 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const teamHandoffs = [
{ from: 'Design', to: 'Build', count: 84 },
{ from: 'Build', to: 'Review', count: 68 },
];
```
One row per directed source/target pair. Aggregate duplicate pairs first. Ribbon width encodes flow and color identifies the source. Node sectors and legend totals include incoming plus outgoing flow; the headline counts each row once. Self-links and negative values are rejected. Null and zero do not invent a flow.
### Hover
Ribbons weave across the frame on entrance. The pointer follows each silhouette, so gaps stay open. Hover or focus to read the original observation in the headline. Click or press Enter to pin; Escape releases. Arrow keys, Home, and End move between marks. Touch dragging inspects and lifting pins. Loading uses shaped shimmer, staggered draw, or breathe placeholders, holds through its opacity exit, then reveals the data. Refreshes retain accepted data. Reduced motion keeps inspection feedback and skips decorative animation.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 340. Dense data can expand or scroll to preserve geometry.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `source` (`text key of Row`): Source node; nodes retain first-seen order.
- `target` (`text key of Row`): Destination node. Must differ from source.
- `value` (`numeric key of Row`): Nonnegative flow. Null is missing; zero has no ribbon but remains in the accessible table.
- `tilt` (`number`): Vertical proportion of the ring, 0.4 to 1, default 0.68.
- `gap` (`number`): Gap between node sectors in radians, 0 to 0.16, default 0.06.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Rounded-square legend with group inspection and pinning. Defaults to tiles; false removes it.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Marker beside each group label, where a group legend is present. Defaults to square.
## Rank ribbons: `RankRibbonsCard`
Follow a leaderboard as its tracks climb, cross, and change places. Docs: https://liltui.vercel.app/charts/rank-ribbons
```tsx
import { RankRibbonsCard } from '@lilt-ui/charts';
```
### Complete examples
#### Product league
```tsx
'use client';
import { RankRibbonsCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const productLeague = [
{ "product": "Orbit", "month": "Apr", "score": 92 },
{ "product": "Orbit", "month": "May", "score": 88 },
{ "product": "Orbit", "month": "Jun", "score": 84 },
{ "product": "Orbit", "month": "Jul", "score": 90 },
{ "product": "Orbit", "month": "Aug", "score": 96 },
{ "product": "Orbit", "month": "Sep", "score": 98 },
{ "product": "Field", "month": "Apr", "score": 72 },
{ "product": "Field", "month": "May", "score": 86 },
{ "product": "Field", "month": "Jun", "score": 94 },
{ "product": "Field", "month": "Jul", "score": 96 },
{ "product": "Field", "month": "Aug", "score": 90 },
{ "product": "Field", "month": "Sep", "score": 93 },
{ "product": "Forma", "month": "Apr", "score": 86 },
{ "product": "Forma", "month": "May", "score": 92 },
{ "product": "Forma", "month": "Jun", "score": 90 },
{ "product": "Forma", "month": "Jul", "score": 85 },
{ "product": "Forma", "month": "Aug", "score": 82 },
{ "product": "Forma", "month": "Sep", "score": 88 },
{ "product": "Muse", "month": "Apr", "score": 65 },
{ "product": "Muse", "month": "May", "score": 70 },
{ "product": "Muse", "month": "Jun", "score": 78 },
{ "product": "Muse", "month": "Jul", "score": 86 },
{ "product": "Muse", "month": "Aug", "score": 92 },
{ "product": "Muse", "month": "Sep", "score": 96 },
{ "product": "Dawn", "month": "Apr", "score": 78 },
{ "product": "Dawn", "month": "May", "score": 76 },
{ "product": "Dawn", "month": "Jun", "score": 72 },
{ "product": "Dawn", "month": "Jul", "score": 74 },
{ "product": "Dawn", "month": "Aug", "score": 80 },
{ "product": "Dawn", "month": "Sep", "score": 84 },
];
export function Example() {
return (
);
}
```
#### Interrupted reporting
A product can miss a report and rejoin later; the ribbon never bridges missing periods.
```tsx
'use client';
import { RankRibbonsCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const leagueWithGaps = [
{ "product": "Orbit", "month": "Apr", "score": 92 },
{ "product": "Orbit", "month": "May", "score": 88 },
{ "product": "Orbit", "month": "Jun", "score": 84 },
{ "product": "Orbit", "month": "Jul", "score": 90 },
{ "product": "Orbit", "month": "Aug", "score": 96 },
{ "product": "Orbit", "month": "Sep", "score": 98 },
{ "product": "Field", "month": "Apr", "score": 72 },
{ "product": "Field", "month": "May", "score": 86 },
{ "product": "Field", "month": "Jun", "score": null },
{ "product": "Field", "month": "Jul", "score": null },
{ "product": "Field", "month": "Aug", "score": 90 },
{ "product": "Field", "month": "Sep", "score": 93 },
{ "product": "Forma", "month": "Apr", "score": 86 },
{ "product": "Forma", "month": "May", "score": 92 },
{ "product": "Forma", "month": "Jun", "score": 90 },
{ "product": "Forma", "month": "Jul", "score": 85 },
{ "product": "Forma", "month": "Aug", "score": 82 },
{ "product": "Forma", "month": "Sep", "score": 88 },
{ "product": "Muse", "month": "Apr", "score": 65 },
{ "product": "Muse", "month": "May", "score": 70 },
{ "product": "Muse", "month": "Jun", "score": 78 },
{ "product": "Muse", "month": "Jul", "score": null },
{ "product": "Muse", "month": "Aug", "score": 92 },
{ "product": "Muse", "month": "Sep", "score": 96 },
{ "product": "Dawn", "month": "Apr", "score": 78 },
{ "product": "Dawn", "month": "May", "score": 76 },
{ "product": "Dawn", "month": "Jun", "score": 72 },
{ "product": "Dawn", "month": "Jul", "score": 74 },
{ "product": "Dawn", "month": "Aug", "score": 80 },
{ "product": "Dawn", "month": "Sep", "score": 84 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const productLeague = [
{ product: 'Orbit', month: 'Apr', score: 92 },
{ product: 'Field', month: 'Apr', score: 72 },
{ product: 'Orbit', month: 'May', score: 88 },
];
```
One row per series and period; periods stay in first-seen order. Scores determine ranks independently each period. Equal scores share a competition rank (1, 1, 3). Missing values break the track. The resting headline is the mean of known scores; inspection reports the original score and rank, and the legend reports the final period score.
### Hover
Tracks weave from left to right. Inspecting a segment highlights the whole series and reads the segment’s ending period. Hover or focus to read the original observation in the headline. Click or press Enter to pin; Escape releases. Arrow keys, Home, and End move between marks. Touch dragging inspects and lifting pins. Loading uses shaped shimmer, staggered draw, or breathe placeholders, holds through its opacity exit, then reveals the data. Refreshes retain accepted data. Reduced motion keeps inspection feedback and skips decorative animation.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 300. Dense data can expand or scroll to preserve geometry.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting score summary; defaults to mean.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `series` (`text key of Row`): One colored track per series.
- `period` (`text key of Row`): Time period, in first-seen order.
- `value` (`numeric key of Row`): Score used to derive rank and shown in the readout.
- `order` (`'descending' | 'ascending'`): Descending (default) ranks the largest value first; ascending ranks the smallest first.
- `thickness` (`number`): Track width, 3 to 18 pixels, default 10.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Rounded-square legend with group inspection and pinning. Defaults to tiles; false removes it.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Marker beside each group label, where a group legend is present. Defaults to square.
## Event helix: `EventHelixCard`
Events climb a coil: recurring times line up while each new cycle rises above the last. Docs: https://liltui.vercel.app/charts/event-helix
```tsx
import { EventHelixCard } from '@lilt-ui/charts';
```
### Complete examples
#### Service activity
```tsx
'use client';
import { EventHelixCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const serviceEvents = [
{ "event": "Run 01", "at": "2026-09-28T02:00:00.000Z", "service": "API", "requests": 12 },
{ "event": "Run 02", "at": "2026-09-28T06:00:00.000Z", "service": "Workers", "requests": 29 },
{ "event": "Run 03", "at": "2026-09-28T09:00:00.000Z", "service": "Edge", "requests": 46 },
{ "event": "Run 04", "at": "2026-09-28T12:00:00.000Z", "service": "API", "requests": 63 },
{ "event": "Run 05", "at": "2026-09-28T16:00:00.000Z", "service": "Workers", "requests": 80 },
{ "event": "Run 06", "at": "2026-09-28T21:00:00.000Z", "service": "Edge", "requests": 17 },
{ "event": "Run 07", "at": "2026-09-29T02:00:00.000Z", "service": "API", "requests": 34 },
{ "event": "Run 08", "at": "2026-09-29T06:00:00.000Z", "service": "Workers", "requests": 51 },
{ "event": "Run 09", "at": "2026-09-29T09:00:00.000Z", "service": "Edge", "requests": 68 },
{ "event": "Run 10", "at": "2026-09-29T12:00:00.000Z", "service": "API", "requests": 85 },
{ "event": "Run 11", "at": "2026-09-29T16:00:00.000Z", "service": "Workers", "requests": 22 },
{ "event": "Run 12", "at": "2026-09-29T21:00:00.000Z", "service": "Edge", "requests": 39 },
{ "event": "Run 13", "at": "2026-09-30T02:00:00.000Z", "service": "API", "requests": 56 },
{ "event": "Run 14", "at": "2026-09-30T06:00:00.000Z", "service": "Workers", "requests": 73 },
{ "event": "Run 15", "at": "2026-09-30T09:00:00.000Z", "service": "Edge", "requests": 90 },
{ "event": "Run 16", "at": "2026-09-30T12:00:00.000Z", "service": "API", "requests": 27 },
{ "event": "Run 17", "at": "2026-09-30T16:00:00.000Z", "service": "Workers", "requests": 44 },
{ "event": "Run 18", "at": "2026-09-30T21:00:00.000Z", "service": "Edge", "requests": 61 },
{ "event": "Run 19", "at": "2026-10-01T02:00:00.000Z", "service": "API", "requests": 78 },
{ "event": "Run 20", "at": "2026-10-01T06:00:00.000Z", "service": "Workers", "requests": 15 },
{ "event": "Run 21", "at": "2026-10-01T09:00:00.000Z", "service": "Edge", "requests": 32 },
{ "event": "Run 22", "at": "2026-10-01T12:00:00.000Z", "service": "API", "requests": 49 },
{ "event": "Run 23", "at": "2026-10-01T16:00:00.000Z", "service": "Workers", "requests": 66 },
{ "event": "Run 24", "at": "2026-10-01T21:00:00.000Z", "service": "Edge", "requests": 83 },
{ "event": "Run 25", "at": "2026-10-02T02:00:00.000Z", "service": "API", "requests": 20 },
{ "event": "Run 26", "at": "2026-10-02T06:00:00.000Z", "service": "Workers", "requests": 37 },
{ "event": "Run 27", "at": "2026-10-02T09:00:00.000Z", "service": "Edge", "requests": 54 },
{ "event": "Run 28", "at": "2026-10-02T12:00:00.000Z", "service": "API", "requests": 71 },
{ "event": "Run 29", "at": "2026-10-02T16:00:00.000Z", "service": "Workers", "requests": 88 },
{ "event": "Run 30", "at": "2026-10-02T21:00:00.000Z", "service": "Edge", "requests": 25 },
];
export function Example() {
return (
);
}
```
#### An afternoon burst
Several closely timed events collect on one part of the coil while the rest retain their positions.
```tsx
'use client';
import { EventHelixCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const eventBurst = [
{ "event": "Run 01", "at": "2026-09-28T02:00:00.000Z", "service": "API", "requests": 12 },
{ "event": "Run 02", "at": "2026-09-28T06:00:00.000Z", "service": "Workers", "requests": 29 },
{ "event": "Run 03", "at": "2026-09-28T09:00:00.000Z", "service": "Edge", "requests": 46 },
{ "event": "Run 04", "at": "2026-09-28T12:00:00.000Z", "service": "API", "requests": 63 },
{ "event": "Run 05", "at": "2026-09-28T16:00:00.000Z", "service": "Workers", "requests": 80 },
{ "event": "Run 06", "at": "2026-09-28T21:00:00.000Z", "service": "Edge", "requests": 17 },
{ "event": "Run 07", "at": "2026-09-29T02:00:00.000Z", "service": "API", "requests": 34 },
{ "event": "Run 08", "at": "2026-09-29T06:00:00.000Z", "service": "Workers", "requests": 51 },
{ "event": "Run 09", "at": "2026-09-29T09:00:00.000Z", "service": "Edge", "requests": 68 },
{ "event": "Run 10", "at": "2026-09-29T12:00:00.000Z", "service": "API", "requests": 85 },
{ "event": "Run 11", "at": "2026-09-29T16:00:00.000Z", "service": "Workers", "requests": 22 },
{ "event": "Run 12", "at": "2026-09-29T21:00:00.000Z", "service": "Edge", "requests": 39 },
{ "event": "Run 13", "at": "2026-09-30T02:00:00.000Z", "service": "API", "requests": 56 },
{ "event": "Run 14", "at": "2026-09-30T06:00:00.000Z", "service": "Workers", "requests": 73 },
{ "event": "Run 15", "at": "2026-09-30T09:00:00.000Z", "service": "Edge", "requests": 90 },
{ "event": "Run 16", "at": "2026-09-30T12:00:00.000Z", "service": "API", "requests": 27 },
{ "event": "Run 17", "at": "2026-09-30T14:00:00.000Z", "service": "Workers", "requests": 44 },
{ "event": "Run 18", "at": "2026-09-30T14:08:00.000Z", "service": "Edge", "requests": 61 },
{ "event": "Run 19", "at": "2026-09-30T14:16:00.000Z", "service": "API", "requests": 180 },
{ "event": "Run 20", "at": "2026-09-30T14:24:00.000Z", "service": "Workers", "requests": 15 },
{ "event": "Run 21", "at": "2026-09-30T14:32:00.000Z", "service": "Edge", "requests": 32 },
{ "event": "Run 22", "at": "2026-09-30T14:40:00.000Z", "service": "API", "requests": 49 },
{ "event": "Run 23", "at": "2026-10-01T16:00:00.000Z", "service": "Workers", "requests": 66 },
{ "event": "Run 24", "at": "2026-10-01T21:00:00.000Z", "service": "Edge", "requests": 83 },
{ "event": "Run 25", "at": "2026-10-02T02:00:00.000Z", "service": "API", "requests": 20 },
{ "event": "Run 26", "at": "2026-10-02T06:00:00.000Z", "service": "Workers", "requests": 37 },
{ "event": "Run 27", "at": "2026-10-02T09:00:00.000Z", "service": "Edge", "requests": 54 },
{ "event": "Run 28", "at": "2026-10-02T12:00:00.000Z", "service": "API", "requests": 71 },
{ "event": "Run 29", "at": "2026-10-02T16:00:00.000Z", "service": "Workers", "requests": 88 },
{ "event": "Run 30", "at": "2026-10-02T21:00:00.000Z", "service": "Edge", "requests": 25 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const serviceEvents = [
{ event: 'Run 01', at: '2026-09-28T02:00:00Z', service: 'API', requests: 12 },
{ event: 'Run 02', at: '2026-09-28T06:00:00Z', service: 'Workers', requests: 29 },
];
```
Each event has a unique label, timestamp and nonnegative magnitude. Dates accept Date objects, epoch milliseconds or ISO strings with explicit time zones (plain ISO dates are UTC). Events are sorted chronologically; simultaneous events remain individually keyboard-accessible. Daily turns start at UTC midnight; weekly turns start Monday. At most 60 cycles fit one view. Null magnitudes stay marked as missing; zero is a small measured bead.
### Hover
The coil grows upward and beads arrive in time order. Hover or focus to read the original observation in the headline. Click or press Enter to pin; Escape releases. Arrow keys, Home, and End move between marks. Touch dragging inspects and lifting pins. Loading uses shaped shimmer, staggered draw, or breathe placeholders, holds through its opacity exit, then reveals the data. Refreshes retain accepted data. Reduced motion keeps inspection feedback and skips decorative animation.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 360. Dense data can expand or scroll to preserve geometry.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `label` (`text key of Row`): Unique event name.
- `date` (`date, string, or numeric key of Row`): Event timestamp, interpreted in UTC.
- `value` (`numeric key of Row`): Nonnegative magnitude, encoded by bead size.
- `group` (`text key of Row`): Optional category color and legend.
- `cycle` (`'day' | 'week'`): One revolution per day (default) or week.
- `pitch` (`number`): Minimum turn spacing, 26 to 100 pixels, default 54.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Rounded-square legend with group inspection and pinning. Defaults to tiles; false removes it.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Marker beside each group label, where a group legend is present. Defaults to square.
## Contour islands: `ContourIslandsCard`
Clusters become contour terraces, with the actual observations still visible on their surface. Docs: https://liltui.vercel.app/charts/contour-islands
```tsx
import { ContourIslandsCard } from '@lilt-ui/charts';
```
### Complete examples
#### Customer activity
```tsx
'use client';
import { ContourIslandsCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const customerCloud = [
{ "account": "Account 01", "sessions": 28, "actions": 41, "seats": 1 },
{ "account": "Account 02", "sessions": 81, "actions": 69, "seats": 2 },
{ "account": "Account 03", "sessions": 55, "actions": 17, "seats": 3 },
{ "account": "Account 04", "sessions": 33, "actions": 40, "seats": 4 },
{ "account": "Account 05", "sessions": 77, "actions": 76, "seats": 5 },
{ "account": "Account 06", "sessions": 56, "actions": 17, "seats": 6 },
{ "account": "Account 07", "sessions": 37, "actions": 32, "seats": 7 },
{ "account": "Account 08", "sessions": 69, "actions": 78, "seats": 8 },
{ "account": "Account 09", "sessions": 64, "actions": 27, "seats": 1 },
{ "account": "Account 10", "sessions": 33, "actions": 27, "seats": 2 },
{ "account": "Account 11", "sessions": 66, "actions": 68, "seats": 3 },
{ "account": "Account 12", "sessions": 73, "actions": 25, "seats": 4 },
{ "account": "Account 13", "sessions": 20, "actions": 38, "seats": 5 },
{ "account": "Account 14", "sessions": 77, "actions": 65, "seats": 6 },
{ "account": "Account 15", "sessions": 63, "actions": 24, "seats": 7 },
{ "account": "Account 16", "sessions": 23, "actions": 44, "seats": 8 },
{ "account": "Account 17", "sessions": 82, "actions": 65, "seats": 1 },
{ "account": "Account 18", "sessions": 60, "actions": 16, "seats": 2 },
{ "account": "Account 19", "sessions": 22, "actions": 46, "seats": 3 },
{ "account": "Account 20", "sessions": 87, "actions": 75, "seats": 4 },
{ "account": "Account 21", "sessions": 52, "actions": 11, "seats": 5 },
{ "account": "Account 22", "sessions": 29, "actions": 35, "seats": 6 },
{ "account": "Account 23", "sessions": 85, "actions": 73, "seats": 7 },
{ "account": "Account 24", "sessions": 47, "actions": 22, "seats": 8 },
{ "account": "Account 25", "sessions": 40, "actions": 33, "seats": 1 },
{ "account": "Account 26", "sessions": 73, "actions": 72, "seats": 2 },
{ "account": "Account 27", "sessions": 59, "actions": 28, "seats": 3 },
{ "account": "Account 28", "sessions": 32, "actions": 33, "seats": 4 },
{ "account": "Account 29", "sessions": 73, "actions": 63, "seats": 5 },
{ "account": "Account 30", "sessions": 63, "actions": 30, "seats": 6 },
{ "account": "Account 31", "sessions": 30, "actions": 44, "seats": 7 },
{ "account": "Account 32", "sessions": 71, "actions": 59, "seats": 8 },
{ "account": "Account 33", "sessions": 69, "actions": 19, "seats": 1 },
{ "account": "Account 34", "sessions": 22, "actions": 41, "seats": 2 },
{ "account": "Account 35", "sessions": 77, "actions": 70, "seats": 3 },
{ "account": "Account 36", "sessions": 69, "actions": 17, "seats": 4 },
{ "account": "Account 37", "sessions": 15, "actions": 40, "seats": 5 },
{ "account": "Account 38", "sessions": 88, "actions": 76, "seats": 6 },
{ "account": "Account 39", "sessions": 59, "actions": 18, "seats": 7 },
{ "account": "Account 40", "sessions": 26, "actions": 31, "seats": 8 },
{ "account": "Account 41", "sessions": 82, "actions": 78, "seats": 1 },
{ "account": "Account 42", "sessions": 56, "actions": 28, "seats": 2 },
{ "account": "Account 43", "sessions": 30, "actions": 27, "seats": 3 },
{ "account": "Account 44", "sessions": 81, "actions": 66, "seats": 4 },
{ "account": "Account 45", "sessions": 52, "actions": 25, "seats": 5 },
{ "account": "Account 46", "sessions": 36, "actions": 38, "seats": 6 },
{ "account": "Account 47", "sessions": 74, "actions": 65, "seats": 7 },
{ "account": "Account 48", "sessions": 57, "actions": 24, "seats": 8 },
{ "account": "Account 49", "sessions": 38, "actions": 44, "seats": 1 },
{ "account": "Account 50", "sessions": 65, "actions": 66, "seats": 2 },
{ "account": "Account 51", "sessions": 68, "actions": 15, "seats": 3 },
{ "account": "Account 52", "sessions": 30, "actions": 45, "seats": 4 },
{ "account": "Account 53", "sessions": 76, "actions": 76, "seats": 5 },
{ "account": "Account 54", "sessions": 64, "actions": 11, "seats": 6 },
{ "account": "Account 55", "sessions": 24, "actions": 34, "seats": 7 },
{ "account": "Account 56", "sessions": 78, "actions": 73, "seats": 8 },
{ "account": "Account 57", "sessions": 64, "actions": 22, "seats": 1 },
{ "account": "Account 58", "sessions": 20, "actions": 33, "seats": 2 },
{ "account": "Account 59", "sessions": 85, "actions": 71, "seats": 3 },
{ "account": "Account 60", "sessions": 58, "actions": 29, "seats": 4 },
{ "account": "Account 61", "sessions": 23, "actions": 34, "seats": 5 },
{ "account": "Account 62", "sessions": 89, "actions": 63, "seats": 6 },
{ "account": "Account 63", "sessions": 48, "actions": 29, "seats": 7 },
{ "account": "Account 64", "sessions": 33, "actions": 45, "seats": 8 },
{ "account": "Account 65", "sessions": 83, "actions": 60, "seats": 1 },
{ "account": "Account 66", "sessions": 57, "actions": 17, "seats": 2 },
{ "account": "Account 67", "sessions": 32, "actions": 41, "seats": 3 },
{ "account": "Account 68", "sessions": 75, "actions": 70, "seats": 4 },
{ "account": "Account 69", "sessions": 59, "actions": 17, "seats": 5 },
{ "account": "Account 70", "sessions": 34, "actions": 39, "seats": 6 },
{ "account": "Account 71", "sessions": 70, "actions": 77, "seats": 7 },
{ "account": "Account 72", "sessions": 66, "actions": 18, "seats": 8 },
];
export function Example() {
return (
);
}
```
#### Seats behind the activity
Weighting by seats reveals where larger accounts concentrate, using the same observed coordinates.
```tsx
'use client';
import { ContourIslandsCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const customerCloud = [
{ "account": "Account 01", "sessions": 28, "actions": 41, "seats": 1 },
{ "account": "Account 02", "sessions": 81, "actions": 69, "seats": 2 },
{ "account": "Account 03", "sessions": 55, "actions": 17, "seats": 3 },
{ "account": "Account 04", "sessions": 33, "actions": 40, "seats": 4 },
{ "account": "Account 05", "sessions": 77, "actions": 76, "seats": 5 },
{ "account": "Account 06", "sessions": 56, "actions": 17, "seats": 6 },
{ "account": "Account 07", "sessions": 37, "actions": 32, "seats": 7 },
{ "account": "Account 08", "sessions": 69, "actions": 78, "seats": 8 },
{ "account": "Account 09", "sessions": 64, "actions": 27, "seats": 1 },
{ "account": "Account 10", "sessions": 33, "actions": 27, "seats": 2 },
{ "account": "Account 11", "sessions": 66, "actions": 68, "seats": 3 },
{ "account": "Account 12", "sessions": 73, "actions": 25, "seats": 4 },
{ "account": "Account 13", "sessions": 20, "actions": 38, "seats": 5 },
{ "account": "Account 14", "sessions": 77, "actions": 65, "seats": 6 },
{ "account": "Account 15", "sessions": 63, "actions": 24, "seats": 7 },
{ "account": "Account 16", "sessions": 23, "actions": 44, "seats": 8 },
{ "account": "Account 17", "sessions": 82, "actions": 65, "seats": 1 },
{ "account": "Account 18", "sessions": 60, "actions": 16, "seats": 2 },
{ "account": "Account 19", "sessions": 22, "actions": 46, "seats": 3 },
{ "account": "Account 20", "sessions": 87, "actions": 75, "seats": 4 },
{ "account": "Account 21", "sessions": 52, "actions": 11, "seats": 5 },
{ "account": "Account 22", "sessions": 29, "actions": 35, "seats": 6 },
{ "account": "Account 23", "sessions": 85, "actions": 73, "seats": 7 },
{ "account": "Account 24", "sessions": 47, "actions": 22, "seats": 8 },
{ "account": "Account 25", "sessions": 40, "actions": 33, "seats": 1 },
{ "account": "Account 26", "sessions": 73, "actions": 72, "seats": 2 },
{ "account": "Account 27", "sessions": 59, "actions": 28, "seats": 3 },
{ "account": "Account 28", "sessions": 32, "actions": 33, "seats": 4 },
{ "account": "Account 29", "sessions": 73, "actions": 63, "seats": 5 },
{ "account": "Account 30", "sessions": 63, "actions": 30, "seats": 6 },
{ "account": "Account 31", "sessions": 30, "actions": 44, "seats": 7 },
{ "account": "Account 32", "sessions": 71, "actions": 59, "seats": 8 },
{ "account": "Account 33", "sessions": 69, "actions": 19, "seats": 1 },
{ "account": "Account 34", "sessions": 22, "actions": 41, "seats": 2 },
{ "account": "Account 35", "sessions": 77, "actions": 70, "seats": 3 },
{ "account": "Account 36", "sessions": 69, "actions": 17, "seats": 4 },
{ "account": "Account 37", "sessions": 15, "actions": 40, "seats": 5 },
{ "account": "Account 38", "sessions": 88, "actions": 76, "seats": 6 },
{ "account": "Account 39", "sessions": 59, "actions": 18, "seats": 7 },
{ "account": "Account 40", "sessions": 26, "actions": 31, "seats": 8 },
{ "account": "Account 41", "sessions": 82, "actions": 78, "seats": 1 },
{ "account": "Account 42", "sessions": 56, "actions": 28, "seats": 2 },
{ "account": "Account 43", "sessions": 30, "actions": 27, "seats": 3 },
{ "account": "Account 44", "sessions": 81, "actions": 66, "seats": 4 },
{ "account": "Account 45", "sessions": 52, "actions": 25, "seats": 5 },
{ "account": "Account 46", "sessions": 36, "actions": 38, "seats": 6 },
{ "account": "Account 47", "sessions": 74, "actions": 65, "seats": 7 },
{ "account": "Account 48", "sessions": 57, "actions": 24, "seats": 8 },
{ "account": "Account 49", "sessions": 38, "actions": 44, "seats": 1 },
{ "account": "Account 50", "sessions": 65, "actions": 66, "seats": 2 },
{ "account": "Account 51", "sessions": 68, "actions": 15, "seats": 3 },
{ "account": "Account 52", "sessions": 30, "actions": 45, "seats": 4 },
{ "account": "Account 53", "sessions": 76, "actions": 76, "seats": 5 },
{ "account": "Account 54", "sessions": 64, "actions": 11, "seats": 6 },
{ "account": "Account 55", "sessions": 24, "actions": 34, "seats": 7 },
{ "account": "Account 56", "sessions": 78, "actions": 73, "seats": 8 },
{ "account": "Account 57", "sessions": 64, "actions": 22, "seats": 1 },
{ "account": "Account 58", "sessions": 20, "actions": 33, "seats": 2 },
{ "account": "Account 59", "sessions": 85, "actions": 71, "seats": 3 },
{ "account": "Account 60", "sessions": 58, "actions": 29, "seats": 4 },
{ "account": "Account 61", "sessions": 23, "actions": 34, "seats": 5 },
{ "account": "Account 62", "sessions": 89, "actions": 63, "seats": 6 },
{ "account": "Account 63", "sessions": 48, "actions": 29, "seats": 7 },
{ "account": "Account 64", "sessions": 33, "actions": 45, "seats": 8 },
{ "account": "Account 65", "sessions": 83, "actions": 60, "seats": 1 },
{ "account": "Account 66", "sessions": 57, "actions": 17, "seats": 2 },
{ "account": "Account 67", "sessions": 32, "actions": 41, "seats": 3 },
{ "account": "Account 68", "sessions": 75, "actions": 70, "seats": 4 },
{ "account": "Account 69", "sessions": 59, "actions": 17, "seats": 5 },
{ "account": "Account 70", "sessions": 34, "actions": 39, "seats": 6 },
{ "account": "Account 71", "sessions": 70, "actions": 77, "seats": 7 },
{ "account": "Account 72", "sessions": 66, "actions": 18, "seats": 8 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const customerCloud = [
{ account: 'A', sessions: 28, actions: 38, seats: 4 },
{ account: 'B', sessions: 78, actions: 70, seats: 2 },
];
```
One uniquely named observation per row. A Gaussian kernel estimates density on a fixed grid; contour levels are fractions of the peak density in this view. Contours show an estimate, never an exact count or a geographic boundary. Dots preserve measured x and y with a decorative vertical lift onto their terrace. Missing coordinates remain in the accessible table but have no position. Weights are optional and nonnegative; zero contributes no density. Without weights, the headline counts located observations.
### Hover
Terraces rise from the outside inward, then observation dots appear. Hover reports the original coordinates and weight, not the smoothed density. Hover or focus to read the original observation in the headline. Click or press Enter to pin; Escape releases. Arrow keys, Home, and End move between marks. Touch dragging inspects and lifting pins. Loading uses shaped shimmer, staggered draw, or breathe placeholders, holds through its opacity exit, then reveals the data. Refreshes retain accepted data. Reduced motion keeps inspection feedback and skips decorative animation.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 320. Dense data can expand or scroll to preserve geometry.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `x` (`numeric key of Row`): Horizontal coordinate.
- `y` (`numeric key of Row`): Vertical coordinate.
- `label` (`text key of Row`): Unique observation name.
- `weight` (`numeric key of Row`): Optional nonnegative density weight; omitted means one per observation.
- `bandwidth` (`number`): Kernel width as a fraction of each axis span, 0.04 to 0.25, default 0.1.
- `levels` (`number`): Number of contour terraces, 3 to 9, default 6.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Parallel ribbons: `ParallelRibbonsCard`
Trace a profile through several metrics and find the tradeoffs that one score would hide. Docs: https://liltui.vercel.app/charts/parallel-ribbons
```tsx
import { ParallelRibbonsCard } from '@lilt-ui/charts';
```
### Complete examples
#### Product profiles
```tsx
'use client';
import { ParallelRibbonsCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const productProfiles = [
{ "product": "Orbit", "speed": 92, "quality": 88, "cost": 42, "reach": 75 },
{ "product": "Field", "speed": 72, "quality": 96, "cost": 68, "reach": 90 },
{ "product": "Forma", "speed": 86, "quality": 74, "cost": 28, "reach": 60 },
{ "product": "Muse", "speed": 65, "quality": 92, "cost": 56, "reach": 98 },
{ "product": "Dawn", "speed": 78, "quality": 80, "cost": 35, "reach": 72 },
];
export function Example() {
return (
);
}
```
#### Incomplete profiles
Missing measurements leave a break in the record instead of becoming zeros or interpolated values.
```tsx
'use client';
import { ParallelRibbonsCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const profilesWithGaps = [
{ "product": "Orbit", "speed": 92, "quality": 88, "cost": 42, "reach": 75 },
{ "product": "Field", "speed": 72, "quality": null, "cost": 68, "reach": 90 },
{ "product": "Forma", "speed": 86, "quality": 74, "cost": 28, "reach": 60 },
{ "product": "Muse", "speed": 65, "quality": 92, "cost": null, "reach": 98 },
{ "product": "Dawn", "speed": 78, "quality": 80, "cost": 35, "reach": 72 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const productProfiles = [
{ product: 'Orbit', speed: 92, quality: 88, cost: 42, reach: 75 },
{ product: 'Field', speed: 72, quality: 96, cost: 68, reach: 90 },
];
```
One unique label per record and at least two distinct numeric metric keys. Each axis uses its own observed min/max or a supplied domain; constant axes place values in the middle. Missing readings break the ribbon. The resting headline counts records instead of adding unlike metrics; inspection reads the original value at the ending axis. Higher on an axis means larger, not necessarily better.
### Hover
Threads weave across the axes. Inspecting a segment keeps the whole record lit while other records soften. Hover or focus to read the original observation in the headline. Click or press Enter to pin; Escape releases. Arrow keys, Home, and End move between marks. Touch dragging inspects and lifting pins. Loading uses shaped shimmer, staggered draw, or breathe placeholders, holds through its opacity exit, then reveals the data. Refreshes retain accepted data. Reduced motion keeps inspection feedback and skips decorative animation.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 300. Dense data can expand or scroll to preserve geometry.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `label` (`text key of Row`): Unique record name and legend label.
- `metrics` (`readonly numeric keys of Row[]`): At least two distinct numeric axes, left to right.
- `metricLabels` (`Partial>`): Optional names printed under each axis.
- `domains` (`Partial>`): Optional fixed finite bounds containing every reading on the axis.
- `thickness` (`number`): Ribbon width, 2 to 14 pixels, default 5.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Rounded-square legend with group inspection and pinning. Defaults to tiles; false removes it.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Marker beside each group label, where a group legend is present. Defaults to square.
## Sunburst terraces: `SunburstTerracesCard`
A hierarchy steps outward through circular terraces; each branch owns its share of the ring. Docs: https://liltui.vercel.app/charts/sunburst-terraces
```tsx
import { SunburstTerracesCard } from '@lilt-ui/charts';
```
### Complete examples
#### Sunburst terraces
```tsx
'use client';
import { SunburstTerracesCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const spatialHierarchy = [
{ "path": "Product/Platform/API", "value": 42 },
{ "path": "Product/Platform/Storage", "value": 26 },
{ "path": "Product/Experience/Web", "value": 32 },
{ "path": "Product/Experience/Mobile", "value": 24 },
{ "path": "Operations/Support", "value": 29 },
{ "path": "Operations/Success", "value": 18 },
{ "path": "Growth/Acquisition", "value": 34 },
{ "path": "Growth/Retention", "value": 22 },
];
export function Example() {
return (
);
}
```
#### Incomplete observations
Missing readings remain missing while the known observations retain their geometry.
```tsx
'use client';
import { SunburstTerracesCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const hierarchyWithGaps = [
{ "path": "Product/Platform/API", "value": 42 },
{ "path": "Product/Platform/Storage", "value": 26 },
{ "path": "Product/Experience/Web", "value": null },
{ "path": "Product/Experience/Mobile", "value": 24 },
{ "path": "Operations/Support", "value": 0 },
{ "path": "Operations/Success", "value": 18 },
{ "path": "Growth/Acquisition", "value": 34 },
{ "path": "Growth/Retention", "value": 22 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const spatialHierarchy = [
{
"path": "Product/Platform/API",
"value": 42
},
{
"path": "Product/Platform/Storage",
"value": 26
},
{
"path": "Product/Experience/Web",
"value": 32
},
{
"path": "Product/Experience/Mobile",
"value": 24
},
{
"path": "Operations/Support",
"value": 29
},
{
"path": "Operations/Success",
"value": 18
},
{
"path": "Growth/Acquisition",
"value": 34
},
{
"path": "Growth/Retention",
"value": 22
}
];
```
Supply leaf-only slash-separated paths, up to eight levels. Branch angles sum known leaf values; missing leaves do not invent area. Zero and missing readings remain in the data table. A path cannot also be an ancestor. Branch selection returns a null datum with a calculated total; leaves return their original row. Terrace height is decorative.
### Hover
Shaped shimmer, staggered draw and breathe placeholders share the existing opacity exit before the entrance reveal. Refreshes retain accepted data. Hover or focus reads the original observation; click or Enter pins it, and Escape releases. Arrow keys, Home and End move between marks; touch dragging inspects and lifting pins. Reduced motion skips decorative animation while preserving inspection feedback.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 360px. Dense data may expand within the scrollable viewport.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `path` (`text key of Row`): Unique leaf path. Separate hierarchy levels with /; do not supply parent-total rows.
- `value` (`numeric key of Row`): Nonnegative numeric measurement. Null or undefined is missing.
- `tilt` (`number`): Vertical proportion of the projected plane, from 0.4 to 1 (Wind rose: 0.45 to 1). Default 0.62.
- `rise` (`number`): Decorative terrace step (0–24px), or Ternary magnitude height (0–80px). Default 12.
- `aggregate` (`'sum' | 'mean' | 'max'`): Fallback resting summary. A family-defined summary (such as located point count, hierarchy total, or mean signed value) takes precedence. Use headline to override that summary.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Marker beside each group label, where a group legend is present. Defaults to square.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Layout for the group legend where the data produces groups. False hides it; defaults to tiles.
## Cluster constellation: `ClusterConstellationCard`
A spatial network of shaded nodes and curved links, with the inspected node’s neighbours kept in view. Docs: https://liltui.vercel.app/charts/cluster-constellation
```tsx
import { ClusterConstellationCard } from '@lilt-ui/charts';
```
### Complete examples
#### Cluster constellation
```tsx
'use client';
import { ClusterConstellationCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const spatialCloud = [
{ "name": "Node 1", "x": 22, "y": 37, "z": 30, "value": 12, "group": "Platform", "links": [
"Node 4",
"Node 7",
] },
{ "name": "Node 2", "x": 85, "y": 36, "z": 78, "value": 29, "group": "Experience", "links": [
"Node 5",
"Node 8",
] },
{ "name": "Node 3", "x": 36, "y": 64, "z": 59, "value": 46, "group": "Growth", "links": [
"Node 6",
"Node 9",
] },
{ "name": "Node 4", "x": 29, "y": 30, "z": 43, "value": 63, "group": "Platform", "links": [
"Node 7",
"Node 10",
] },
{ "name": "Node 5", "x": 79, "y": 48, "z": 73, "value": 80, "group": "Experience", "links": [
"Node 8",
"Node 11",
] },
{ "name": "Node 6", "x": 37, "y": 69, "z": 39, "value": 17, "group": "Growth", "links": [
"Node 9",
"Node 12",
] },
{ "name": "Node 7", "x": 33, "y": 16, "z": 17, "value": 34, "group": "Platform", "links": [
"Node 10",
"Node 13",
] },
{ "name": "Node 8", "x": 71, "y": 47, "z": 53, "value": 51, "group": "Experience", "links": [
"Node 11",
"Node 14",
] },
{ "name": "Node 9", "x": 43, "y": 82, "z": 35, "value": 68, "group": "Growth", "links": [
"Node 12",
"Node 15",
] },
{ "name": "Node 10", "x": 34, "y": 14, "z": 30, "value": 85, "group": "Platform", "links": [
"Node 13",
"Node 16",
] },
{ "name": "Node 11", "x": 66, "y": 35, "z": 78, "value": 22, "group": "Experience", "links": [
"Node 14",
"Node 17",
] },
{ "name": "Node 12", "x": 50, "y": 88, "z": 59, "value": 39, "group": "Growth", "links": [
"Node 15",
"Node 18",
] },
{ "name": "Node 13", "x": 29, "y": 25, "z": 43, "value": 56, "group": "Platform", "links": [
"Node 16",
"Node 19",
] },
{ "name": "Node 14", "x": 64, "y": 26, "z": 73, "value": 73, "group": "Experience", "links": [
"Node 17",
"Node 20",
] },
{ "name": "Node 15", "x": 56, "y": 79, "z": 39, "value": 90, "group": "Growth", "links": [
"Node 18",
"Node 21",
] },
{ "name": "Node 16", "x": 23, "y": 36, "z": 17, "value": 27, "group": "Platform", "links": [
"Node 19",
"Node 22",
] },
{ "name": "Node 17", "x": 67, "y": 32, "z": 53, "value": 44, "group": "Experience", "links": [
"Node 20",
"Node 23",
] },
{ "name": "Node 18", "x": 60, "y": 66, "z": 35, "value": 61, "group": "Growth", "links": [
"Node 21",
"Node 24",
] },
{ "name": "Node 19", "x": 16, "y": 33, "z": 31, "value": 78, "group": "Platform", "links": [
"Node 22",
"Node 25",
] },
{ "name": "Node 20", "x": 73, "y": 46, "z": 78, "value": 15, "group": "Experience", "links": [
"Node 23",
"Node 26",
] },
{ "name": "Node 21", "x": 59, "y": 66, "z": 59, "value": 32, "group": "Growth", "links": [
"Node 24",
"Node 27",
] },
{ "name": "Node 22", "x": 11, "y": 20, "z": 43, "value": 49, "group": "Platform", "links": [
"Node 25",
"Node 28",
] },
{ "name": "Node 23", "x": 80, "y": 49, "z": 73, "value": 66, "group": "Experience", "links": [
"Node 26",
"Node 29",
] },
{ "name": "Node 24", "x": 54, "y": 78, "z": 38, "value": 83, "group": "Growth", "links": [
"Node 27",
"Node 30",
] },
{ "name": "Node 25", "x": 10, "y": 13, "z": 17, "value": 20, "group": "Platform", "links": [
"Node 28",
"Node 1",
] },
{ "name": "Node 26", "x": 86, "y": 39, "z": 53, "value": 37, "group": "Experience", "links": [
"Node 29",
"Node 2",
] },
{ "name": "Node 27", "x": 47, "y": 88, "z": 35, "value": 54, "group": "Growth", "links": [
"Node 30",
"Node 3",
] },
{ "name": "Node 28", "x": 14, "y": 21, "z": 31, "value": 71, "group": "Platform", "links": [
"Node 1",
"Node 4",
] },
{ "name": "Node 29", "x": 88, "y": 27, "z": 78, "value": 88, "group": "Experience", "links": [
"Node 2",
"Node 5",
] },
{ "name": "Node 30", "x": 40, "y": 83, "z": 59, "value": 25, "group": "Growth", "links": [
"Node 3",
"Node 6",
] },
];
export function Example() {
return (
);
}
```
#### Incomplete observations
Missing readings remain missing while the known observations retain their geometry.
```tsx
'use client';
import { ClusterConstellationCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const cloudWithGaps = [
{ "name": "Node 1", "x": 22, "y": 37, "z": 30, "value": 12, "group": "Platform", "links": [
"Node 4",
"Node 7",
] },
{ "name": "Node 2", "x": 85, "y": 36, "z": 78, "value": 29, "group": "Experience", "links": [
"Node 5",
"Node 8",
] },
{ "name": "Node 3", "x": 36, "y": 64, "z": 59, "value": 46, "group": "Growth", "links": [
"Node 6",
"Node 9",
] },
{ "name": "Node 4", "x": 29, "y": 30, "z": null, "value": 63, "group": "Platform", "links": [
"Node 7",
"Node 10",
] },
{ "name": "Node 5", "x": 79, "y": 48, "z": 73, "value": 80, "group": "Experience", "links": [
"Node 8",
"Node 11",
] },
{ "name": "Node 6", "x": 37, "y": 69, "z": 39, "value": 17, "group": "Growth", "links": [
"Node 9",
"Node 12",
] },
{ "name": "Node 7", "x": 33, "y": 16, "z": 17, "value": null, "group": "Platform", "links": [
"Node 10",
"Node 13",
] },
{ "name": "Node 8", "x": 71, "y": 47, "z": 53, "value": 51, "group": "Experience", "links": [
"Node 11",
"Node 14",
] },
{ "name": "Node 9", "x": 43, "y": 82, "z": 35, "value": 68, "group": "Growth", "links": [
"Node 12",
"Node 15",
] },
{ "name": "Node 10", "x": 34, "y": 14, "z": 30, "value": 85, "group": "Platform", "links": [
"Node 13",
"Node 16",
] },
{ "name": "Node 11", "x": 66, "y": 35, "z": 78, "value": 22, "group": "Experience", "links": [
"Node 14",
"Node 17",
] },
{ "name": "Node 12", "x": 50, "y": 88, "z": 59, "value": 39, "group": "Growth", "links": [
"Node 15",
"Node 18",
] },
{ "name": "Node 13", "x": 29, "y": 25, "z": 43, "value": 56, "group": "Platform", "links": [
"Node 16",
"Node 19",
] },
{ "name": "Node 14", "x": 64, "y": 26, "z": 73, "value": 73, "group": "Experience", "links": [
"Node 17",
"Node 20",
] },
{ "name": "Node 15", "x": 56, "y": 79, "z": 39, "value": 90, "group": "Growth", "links": [
"Node 18",
"Node 21",
] },
{ "name": "Node 16", "x": 23, "y": 36, "z": 17, "value": 27, "group": "Platform", "links": [
"Node 19",
"Node 22",
] },
{ "name": "Node 17", "x": 67, "y": 32, "z": 53, "value": 44, "group": "Experience", "links": [
"Node 20",
"Node 23",
] },
{ "name": "Node 18", "x": 60, "y": 66, "z": 35, "value": 61, "group": "Growth", "links": [
"Node 21",
"Node 24",
] },
{ "name": "Node 19", "x": 16, "y": 33, "z": 31, "value": 78, "group": "Platform", "links": [
"Node 22",
"Node 25",
] },
{ "name": "Node 20", "x": 73, "y": 46, "z": 78, "value": 15, "group": "Experience", "links": [
"Node 23",
"Node 26",
] },
{ "name": "Node 21", "x": 59, "y": 66, "z": 59, "value": 32, "group": "Growth", "links": [
"Node 24",
"Node 27",
] },
{ "name": "Node 22", "x": 11, "y": 20, "z": 43, "value": 49, "group": "Platform", "links": [
"Node 25",
"Node 28",
] },
{ "name": "Node 23", "x": 80, "y": 49, "z": 73, "value": 66, "group": "Experience", "links": [
"Node 26",
"Node 29",
] },
{ "name": "Node 24", "x": 54, "y": 78, "z": 38, "value": 83, "group": "Growth", "links": [
"Node 27",
"Node 30",
] },
{ "name": "Node 25", "x": 10, "y": 13, "z": 17, "value": 20, "group": "Platform", "links": [
"Node 28",
"Node 1",
] },
{ "name": "Node 26", "x": 86, "y": 39, "z": 53, "value": 37, "group": "Experience", "links": [
"Node 29",
"Node 2",
] },
{ "name": "Node 27", "x": 47, "y": 88, "z": 35, "value": 54, "group": "Growth", "links": [
"Node 30",
"Node 3",
] },
{ "name": "Node 28", "x": 14, "y": 21, "z": 31, "value": 71, "group": "Platform", "links": [
"Node 1",
"Node 4",
] },
{ "name": "Node 29", "x": 88, "y": 27, "z": 78, "value": 88, "group": "Experience", "links": [
"Node 2",
"Node 5",
] },
{ "name": "Node 30", "x": 40, "y": 83, "z": 59, "value": 25, "group": "Growth", "links": [
"Node 3",
"Node 6",
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const spatialCloud = [
{
"name": "Node 1",
"x": 22,
"y": 37,
"z": 30,
"value": 12,
"group": "Platform",
"links": [
"Node 4",
"Node 7"
]
},
{
"name": "Node 2",
"x": 85,
"y": 36,
"z": 78,
"value": 29,
"group": "Experience",
"links": [
"Node 5",
"Node 8"
]
},
{
"name": "Node 3",
"x": 36,
"y": 64,
"z": 59,
"value": 46,
"group": "Growth",
"links": [
"Node 6",
"Node 9"
]
},
{
"name": "Node 4",
"x": 29,
"y": 30,
"z": 43,
"value": 63,
"group": "Platform",
"links": [
"Node 7",
"Node 10"
]
},
{
"name": "Node 5",
"x": 79,
"y": 48,
"z": 73,
"value": 80,
"group": "Experience",
"links": [
"Node 8",
"Node 11"
]
},
{
"name": "Node 6",
"x": 37,
"y": 69,
"z": 39,
"value": 17,
"group": "Growth",
"links": [
"Node 9",
"Node 12"
]
},
{
"name": "Node 7",
"x": 33,
"y": 16,
"z": 17,
"value": 34,
"group": "Platform",
"links": [
"Node 10",
"Node 13"
]
},
{
"name": "Node 8",
"x": 71,
"y": 47,
"z": 53,
"value": 51,
"group": "Experience",
"links": [
"Node 11",
"Node 14"
]
},
{
"name": "Node 9",
"x": 43,
"y": 82,
"z": 35,
"value": 68,
"group": "Growth",
"links": [
"Node 12",
"Node 15"
]
},
{
"name": "Node 10",
"x": 34,
"y": 14,
"z": 30,
"value": 85,
"group": "Platform",
"links": [
"Node 13",
"Node 16"
]
},
{
"name": "Node 11",
"x": 66,
"y": 35,
"z": 78,
"value": 22,
"group": "Experience",
"links": [
"Node 14",
"Node 17"
]
},
{
"name": "Node 12",
"x": 50,
"y": 88,
"z": 59,
"value": 39,
"group": "Growth",
"links": [
"Node 15",
"Node 18"
]
},
{
"name": "Node 13",
"x": 29,
"y": 25,
"z": 43,
"value": 56,
"group": "Platform",
"links": [
"Node 16",
"Node 19"
]
},
{
"name": "Node 14",
"x": 64,
"y": 26,
"z": 73,
"value": 73,
"group": "Experience",
"links": [
"Node 17",
"Node 20"
]
},
{
"name": "Node 15",
"x": 56,
"y": 79,
"z": 39,
"value": 90,
"group": "Growth",
"links": [
"Node 18",
"Node 21"
]
},
{
"name": "Node 16",
"x": 23,
"y": 36,
"z": 17,
"value": 27,
"group": "Platform",
"links": [
"Node 19",
"Node 22"
]
},
{
"name": "Node 17",
"x": 67,
"y": 32,
"z": 53,
"value": 44,
"group": "Experience",
"links": [
"Node 20",
"Node 23"
]
},
{
"name": "Node 18",
"x": 60,
"y": 66,
"z": 35,
"value": 61,
"group": "Growth",
"links": [
"Node 21",
"Node 24"
]
},
{
"name": "Node 19",
"x": 16,
"y": 33,
"z": 31,
"value": 78,
"group": "Platform",
"links": [
"Node 22",
"Node 25"
]
},
{
"name": "Node 20",
"x": 73,
"y": 46,
"z": 78,
"value": 15,
"group": "Experience",
"links": [
"Node 23",
"Node 26"
]
},
{
"name": "Node 21",
"x": 59,
"y": 66,
"z": 59,
"value": 32,
"group": "Growth",
"links": [
"Node 24",
"Node 27"
]
},
{
"name": "Node 22",
"x": 11,
"y": 20,
"z": 43,
"value": 49,
"group": "Platform",
"links": [
"Node 25",
"Node 28"
]
},
{
"name": "Node 23",
"x": 80,
"y": 49,
"z": 73,
"value": 66,
"group": "Experience",
"links": [
"Node 26",
"Node 29"
]
},
{
"name": "Node 24",
"x": 54,
"y": 78,
"z": 38,
"value": 83,
"group": "Growth",
"links": [
"Node 27",
"Node 30"
]
},
{
"name": "Node 25",
"x": 10,
"y": 13,
"z": 17,
"value": 20,
"group": "Platform",
"links": [
"Node 28",
"Node 1"
]
},
{
"name": "Node 26",
"x": 86,
"y": 39,
"z": 53,
"value": 37,
"group": "Experience",
"links": [
"Node 29",
"Node 2"
]
},
{
"name": "Node 27",
"x": 47,
"y": 88,
"z": 35,
"value": 54,
"group": "Growth",
"links": [
"Node 30",
"Node 3"
]
},
{
"name": "Node 28",
"x": 14,
"y": 21,
"z": 31,
"value": 71,
"group": "Platform",
"links": [
"Node 1",
"Node 4"
]
},
{
"name": "Node 29",
"x": 88,
"y": 27,
"z": 78,
"value": 88,
"group": "Experience",
"links": [
"Node 2",
"Node 5"
]
},
{
"name": "Node 30",
"x": 40,
"y": 83,
"z": 59,
"value": 25,
"group": "Growth",
"links": [
"Node 3",
"Node 6"
]
}
];
```
Supply unique labels, finite XYZ coordinates and arrays of neighbouring labels. Links are undirected and deduplicated; self-links and unknown endpoints are rejected. Positions come from your data rather than a random force simulation. Node area carries magnitude. Missing positions stay in the table. The headline counts located nodes.
### Hover
Shaped shimmer, staggered draw and breathe placeholders share the existing opacity exit before the entrance reveal. Refreshes retain accepted data. Hover or focus reads the original observation; click or Enter pins it, and Escape releases. Arrow keys, Home and End move between marks; touch dragging inspects and lifting pins. Reduced motion skips decorative animation while preserving inspection feedback.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 360px. Dense data may expand within the scrollable viewport.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `label` (`text key of Row`): Unique nonempty observation label, retained through inspection and pinning.
- `x` (`numeric key of Row`): First spatial coordinate on an independent linear scale.
- `y` (`numeric key of Row`): Second spatial coordinate on an independent linear scale.
- `z` (`numeric key of Row`): Third spatial coordinate on an independent linear scale.
- `value` (`numeric key of Row`): Nonnegative numeric measurement. Null or undefined is missing.
- `connections` (`array-of-text key of Row`): Array of existing node labels. Connections are undirected; duplicates and self-links are rejected.
- `group` (`text key of Row`): Optional categorical color key.
- `yaw` (`number`): Camera rotation around the vertical axis, in degrees from -180 to 180. Default 35.
- `elevation` (`number`): Camera elevation, 10 to 70 degrees. Default 25.
- `size` (`number`): Maximum cube half-edge or sphere size as a fraction of the normalized plot, 0.025 to 0.18. Default 0.09.
- `aggregate` (`'sum' | 'mean' | 'max'`): Fallback resting summary. A family-defined summary (such as located point count, hierarchy total, or mean signed value) takes precedence. Use headline to override that summary.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Marker beside each group label, where a group legend is present. Defaults to square.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Layout for the group legend where the data produces groups. False hides it; defaults to tiles.
## Ternary prism: `TernaryPrismCard`
Three competing ingredients find a position on a triangular floor, while magnitude rises above it. Docs: https://liltui.vercel.app/charts/ternary-prism
```tsx
import { TernaryPrismCard } from '@lilt-ui/charts';
```
### Complete examples
#### Ternary prism
```tsx
'use client';
import { TernaryPrismCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ternaryMix = [
{ "name": "Balanced", "a": 34, "b": 33, "c": 33, "value": 48 },
{ "name": "Explorer", "a": 16, "b": 30, "c": 54, "value": 72 },
{ "name": "Builder", "a": 62, "b": 24, "c": 14, "value": 56 },
{ "name": "Connector", "a": 22, "b": 65, "c": 13, "value": 38 },
{ "name": "Generalist", "a": 44, "b": 36, "c": 20, "value": 65 },
{ "name": "Specialist", "a": 8, "b": 18, "c": 74, "value": 86 },
];
export function Example() {
return (
);
}
```
#### Incomplete observations
Missing readings remain missing while the known observations retain their geometry.
```tsx
'use client';
import { TernaryPrismCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const compositionWithGaps = [
{ "name": "Balanced", "a": 34, "b": 33, "c": 33, "value": 48 },
{ "name": "Explorer", "a": 16, "b": 30, "c": 54, "value": 72 },
{ "name": "Builder", "a": null, "b": 24, "c": 14, "value": 56 },
{ "name": "Connector", "a": 22, "b": 65, "c": 13, "value": 38 },
{ "name": "Generalist", "a": 44, "b": 36, "c": 20, "value": 65 },
{ "name": "Specialist", "a": 8, "b": 18, "c": 74, "value": 86 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const ternaryMix = [
{
"name": "Balanced",
"a": 34,
"b": 33,
"c": 33,
"value": 48
},
{
"name": "Explorer",
"a": 16,
"b": 30,
"c": 54,
"value": 72
},
{
"name": "Builder",
"a": 62,
"b": 24,
"c": 14,
"value": 56
},
{
"name": "Connector",
"a": 22,
"b": 65,
"c": 13,
"value": 38
},
{
"name": "Generalist",
"a": 44,
"b": 36,
"c": 20,
"value": 65
},
{
"name": "Specialist",
"a": 8,
"b": 18,
"c": 74,
"value": 86
}
];
```
Three distinct nonnegative measurements are normalized to shares; their original units must be comparable. The floor position encodes the shares, and column height encodes value. A missing part or all-zero composition has no position. The resting headline counts located compositions.
### Hover
Shaped shimmer, staggered draw and breathe placeholders share the existing opacity exit before the entrance reveal. Refreshes retain accepted data. Hover or focus reads the original observation; click or Enter pins it, and Escape releases. Arrow keys, Home and End move between marks; touch dragging inspects and lifting pins. Reduced motion skips decorative animation while preserving inspection feedback.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 340px. Dense data may expand within the scrollable viewport.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `label` (`text key of Row`): Unique nonempty observation label, retained through inspection and pinning.
- `a` (`numeric key of Row`): First nonnegative composition measurement.
- `b` (`numeric key of Row`): Second nonnegative composition measurement.
- `c` (`numeric key of Row`): Third nonnegative composition measurement.
- `value` (`numeric key of Row`): Nonnegative numeric measurement. Null or undefined is missing.
- `tilt` (`number`): Vertical proportion of the projected plane, from 0.4 to 1 (Wind rose: 0.45 to 1). Default 0.65.
- `rise` (`number`): Decorative terrace step (0–24px), or Ternary magnitude height (0–80px). Default 38.
- `aggregate` (`'sum' | 'mean' | 'max'`): Fallback resting summary. A family-defined summary (such as located point count, hierarchy total, or mean signed value) takes precedence. Use headline to override that summary.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Marker beside each group label, where a group legend is present. Defaults to square.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Layout for the group legend where the data produces groups. False hides it; defaults to tiles.
## Wind rose: `WindRoseCard`
Compass petals divide a directional distribution into stacked magnitude bands. Docs: https://liltui.vercel.app/charts/wind-rose
```tsx
import { WindRoseCard } from '@lilt-ui/charts';
```
### Complete examples
#### Wind rose
```tsx
'use client';
import { WindRoseCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const compassBands = [
{ "direction": 0, "band": "Light", "value": 5 },
{ "direction": 0, "band": "Moderate", "value": 18 },
{ "direction": 0, "band": "Strong", "value": 7 },
{ "direction": 45, "band": "Light", "value": 12 },
{ "direction": 45, "band": "Moderate", "value": 25 },
{ "direction": 45, "band": "Strong", "value": 14 },
{ "direction": 90, "band": "Light", "value": 19 },
{ "direction": 90, "band": "Moderate", "value": 8 },
{ "direction": 90, "band": "Strong", "value": 21 },
{ "direction": 135, "band": "Light", "value": 26 },
{ "direction": 135, "band": "Moderate", "value": 15 },
{ "direction": 135, "band": "Strong", "value": 28 },
{ "direction": 180, "band": "Light", "value": 9 },
{ "direction": 180, "band": "Moderate", "value": 22 },
{ "direction": 180, "band": "Strong", "value": 11 },
{ "direction": 225, "band": "Light", "value": 16 },
{ "direction": 225, "band": "Moderate", "value": 5 },
{ "direction": 225, "band": "Strong", "value": 18 },
{ "direction": 270, "band": "Light", "value": 23 },
{ "direction": 270, "band": "Moderate", "value": 12 },
{ "direction": 270, "band": "Strong", "value": 25 },
{ "direction": 315, "band": "Light", "value": 6 },
{ "direction": 315, "band": "Moderate", "value": 19 },
{ "direction": 315, "band": "Strong", "value": 8 },
];
export function Example() {
return (
);
}
```
#### Incomplete observations
Missing readings remain missing while the known observations retain their geometry.
```tsx
'use client';
import { WindRoseCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const windWithGaps = [
{ "direction": 0, "band": "Light", "value": 5 },
{ "direction": 0, "band": "Moderate", "value": 18 },
{ "direction": 0, "band": "Strong", "value": 7 },
{ "direction": 45, "band": "Light", "value": 12 },
{ "direction": 45, "band": "Moderate", "value": null },
{ "direction": 45, "band": "Strong", "value": 14 },
{ "direction": 90, "band": "Light", "value": 19 },
{ "direction": 90, "band": "Moderate", "value": 8 },
{ "direction": 90, "band": "Strong", "value": 21 },
{ "direction": 135, "band": "Light", "value": 0 },
{ "direction": 135, "band": "Moderate", "value": 15 },
{ "direction": 135, "band": "Strong", "value": 28 },
{ "direction": 180, "band": "Light", "value": 9 },
{ "direction": 180, "band": "Moderate", "value": 22 },
{ "direction": 180, "band": "Strong", "value": 11 },
{ "direction": 225, "band": "Light", "value": 16 },
{ "direction": 225, "band": "Moderate", "value": 5 },
{ "direction": 225, "band": "Strong", "value": 18 },
{ "direction": 270, "band": "Light", "value": 23 },
{ "direction": 270, "band": "Moderate", "value": 12 },
{ "direction": 270, "band": "Strong", "value": 25 },
{ "direction": 315, "band": "Light", "value": 6 },
{ "direction": 315, "band": "Moderate", "value": 19 },
{ "direction": 315, "band": "Strong", "value": 8 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const compassBands = [
{
"direction": 0,
"band": "Light",
"value": 5
},
{
"direction": 0,
"band": "Moderate",
"value": 18
},
{
"direction": 0,
"band": "Strong",
"value": 7
},
{
"direction": 45,
"band": "Light",
"value": 12
},
{
"direction": 45,
"band": "Moderate",
"value": 25
},
{
"direction": 45,
"band": "Strong",
"value": 14
},
{
"direction": 90,
"band": "Light",
"value": 19
},
{
"direction": 90,
"band": "Moderate",
"value": 8
},
{
"direction": 90,
"band": "Strong",
"value": 21
},
{
"direction": 135,
"band": "Light",
"value": 26
},
{
"direction": 135,
"band": "Moderate",
"value": 15
},
{
"direction": 135,
"band": "Strong",
"value": 28
},
{
"direction": 180,
"band": "Light",
"value": 9
},
{
"direction": 180,
"band": "Moderate",
"value": 22
},
{
"direction": 180,
"band": "Strong",
"value": 11
},
{
"direction": 225,
"band": "Light",
"value": 16
},
{
"direction": 225,
"band": "Moderate",
"value": 5
},
{
"direction": 225,
"band": "Strong",
"value": 18
},
{
"direction": 270,
"band": "Light",
"value": 23
},
{
"direction": 270,
"band": "Moderate",
"value": 12
},
{
"direction": 270,
"band": "Strong",
"value": 25
},
{
"direction": 315,
"band": "Light",
"value": 6
},
{
"direction": 315,
"band": "Moderate",
"value": 19
},
{
"direction": 315,
"band": "Strong",
"value": 8
}
];
```
Pre-bin observations into equal sectors. Direction is the centre angle, north at 0°, clockwise, and must be a multiple of 360 / sectors. One row per direction and band. Petal area is proportional to frequency, so radius follows the square root of cumulative frequency. Missing and zero values retain distinct table entries.
### Hover
Shaped shimmer, staggered draw and breathe placeholders share the existing opacity exit before the entrance reveal. Refreshes retain accepted data. Hover or focus reads the original observation; click or Enter pins it, and Escape releases. Arrow keys, Home and End move between marks; touch dragging inspects and lifting pins. Reduced motion skips decorative animation while preserving inspection feedback.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 340px. Dense data may expand within the scrollable viewport.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `direction` (`numeric key of Row`): Compass sector centre in degrees, north at 0 and clockwise.
- `band` (`text key of Row`): Magnitude-band label; stacking follows first-seen order.
- `value` (`numeric key of Row`): Nonnegative numeric measurement. Null or undefined is missing.
- `sectors` (`number`): Number of equal compass sectors, 4 to 16. Supply matching pre-binned centre angles. Default 8.
- `tilt` (`number`): Vertical proportion of the projected plane, from 0.4 to 1 (Wind rose: 0.45 to 1). Default 0.76.
- `aggregate` (`'sum' | 'mean' | 'max'`): Fallback resting summary. A family-defined summary (such as located point count, hierarchy total, or mean signed value) takes precedence. Use headline to override that summary.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Marker beside each group label, where a group legend is present. Defaults to square.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Layout for the group legend where the data produces groups. False hides it; defaults to tiles.
## Marimekko blocks: `MarimekkoBlocksCard`
A segmented floor of equal-depth slabs makes category size and composition visible together. Docs: https://liltui.vercel.app/charts/marimekko-blocks
```tsx
import { MarimekkoBlocksCard } from '@lilt-ui/charts';
```
### Complete examples
#### Marimekko blocks
```tsx
'use client';
import { MarimekkoBlocksCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const marketComposition = [
{ "category": "Enterprise", "segment": "Platform", "value": 140 },
{ "category": "Enterprise", "segment": "Services", "value": 157 },
{ "category": "Enterprise", "segment": "Support", "value": 174 },
{ "category": "Mid-market", "segment": "Platform", "value": 116 },
{ "category": "Mid-market", "segment": "Services", "value": 133 },
{ "category": "Mid-market", "segment": "Support", "value": 87 },
{ "category": "Startups", "segment": "Platform", "value": 110 },
{ "category": "Startups", "segment": "Services", "value": 64 },
{ "category": "Startups", "segment": "Support", "value": 81 },
{ "category": "Independent", "segment": "Platform", "value": 60 },
{ "category": "Independent", "segment": "Services", "value": 77 },
{ "category": "Independent", "segment": "Support", "value": 31 },
];
export function Example() {
return (
);
}
```
#### Incomplete observations
Missing readings remain missing while the known observations retain their geometry.
```tsx
'use client';
import { MarimekkoBlocksCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const marketWithGaps = [
{ "category": "Enterprise", "segment": "Platform", "value": 140 },
{ "category": "Enterprise", "segment": "Services", "value": 157 },
{ "category": "Enterprise", "segment": "Support", "value": null },
{ "category": "Mid-market", "segment": "Platform", "value": 116 },
{ "category": "Mid-market", "segment": "Services", "value": 133 },
{ "category": "Mid-market", "segment": "Support", "value": 87 },
{ "category": "Startups", "segment": "Platform", "value": 110 },
{ "category": "Startups", "segment": "Services", "value": 64 },
{ "category": "Startups", "segment": "Support", "value": 81 },
{ "category": "Independent", "segment": "Platform", "value": 60 },
{ "category": "Independent", "segment": "Services", "value": 77 },
{ "category": "Independent", "segment": "Support", "value": 31 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const marketComposition = [
{
"category": "Enterprise",
"segment": "Platform",
"value": 140
},
{
"category": "Enterprise",
"segment": "Services",
"value": 157
},
{
"category": "Enterprise",
"segment": "Support",
"value": 174
},
{
"category": "Mid-market",
"segment": "Platform",
"value": 116
},
{
"category": "Mid-market",
"segment": "Services",
"value": 133
},
{
"category": "Mid-market",
"segment": "Support",
"value": 87
},
{
"category": "Startups",
"segment": "Platform",
"value": 110
},
{
"category": "Startups",
"segment": "Services",
"value": 64
},
{
"category": "Startups",
"segment": "Support",
"value": 81
},
{
"category": "Independent",
"segment": "Platform",
"value": 60
},
{
"category": "Independent",
"segment": "Services",
"value": 77
},
{
"category": "Independent",
"segment": "Support",
"value": 31
}
];
```
One row per category and segment with nonnegative value. Column widths reflect known category totals; subdivisions reflect their shares. All top areas use the same scale and every slab has equal depth. Gaps sit between columns. Missing values are excluded from the known total, retained in the table and never interpreted as zero.
### Hover
Shaped shimmer, staggered draw and breathe placeholders share the existing opacity exit before the entrance reveal. Refreshes retain accepted data. Hover or focus reads the original observation; click or Enter pins it, and Escape releases. Arrow keys, Home and End move between marks; touch dragging inspects and lifting pins. Reduced motion skips decorative animation while preserving inspection feedback.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 340px. Dense data may expand within the scrollable viewport.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `category` (`text key of Row`): Category whose total determines column width.
- `segment` (`text key of Row`): Composition segment and legend identity.
- `value` (`numeric key of Row`): Nonnegative numeric measurement. Null or undefined is missing.
- `gap` (`number`): Space between category columns in floor units, 0 to 0.2. Default 0.06.
- `aggregate` (`'sum' | 'mean' | 'max'`): Fallback resting summary. A family-defined summary (such as located point count, hierarchy total, or mean signed value) takes precedence. Use headline to override that summary.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Marker beside each group label, where a group legend is present. Defaults to square.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Layout for the group legend where the data produces groups. False hides it; defaults to tiles.
## Intersection towers: `IntersectionTowersCard`
Exclusive set overlaps rise as towers above the membership dots that define them. Docs: https://liltui.vercel.app/charts/intersection-towers
```tsx
import { IntersectionTowersCard } from '@lilt-ui/charts';
```
### Complete examples
#### Intersection towers
```tsx
'use client';
import { IntersectionTowersCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const audienceIntersections = [
{ "sets": [
"Search",
], "value": 128 },
{ "sets": [
"Email",
], "value": 96 },
{ "sets": [
"Social",
], "value": 72 },
{ "sets": [
"Search",
"Email",
], "value": 84 },
{ "sets": [
"Search",
"Social",
], "value": 56 },
{ "sets": [
"Email",
"Social",
], "value": 42 },
{ "sets": [
"Search",
"Email",
"Social",
], "value": 32 },
];
export function Example() {
return (
);
}
```
#### Incomplete observations
Missing readings remain missing while the known observations retain their geometry.
```tsx
'use client';
import { IntersectionTowersCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const intersectionWithGaps = [
{ "sets": [
"Search",
], "value": 128 },
{ "sets": [
"Email",
], "value": 96 },
{ "sets": [
"Social",
], "value": 72 },
{ "sets": [
"Search",
"Email",
], "value": null },
{ "sets": [
"Search",
"Social",
], "value": 56 },
{ "sets": [
"Email",
"Social",
], "value": 42 },
{ "sets": [
"Search",
"Email",
"Social",
], "value": 32 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const audienceIntersections = [
{
"sets": [
"Search"
],
"value": 128
},
{
"sets": [
"Email"
],
"value": 96
},
{
"sets": [
"Social"
],
"value": 72
},
{
"sets": [
"Search",
"Email"
],
"value": 84
},
{
"sets": [
"Search",
"Social"
],
"value": 56
},
{
"sets": [
"Email",
"Social"
],
"value": 42
},
{
"sets": [
"Search",
"Email",
"Social"
],
"value": 32
}
];
```
Each row is an exclusive intersection: it belongs to exactly the listed sets and no others. Supply a nonempty array of distinct set names and a nonnegative size. Set order inside a row does not change identity; duplicate intersections are rejected. Missing sizes remain outlined, and sorting puts them after known values.
### Hover
Shaped shimmer, staggered draw and breathe placeholders share the existing opacity exit before the entrance reveal. Refreshes retain accepted data. Hover or focus reads the original observation; click or Enter pins it, and Escape releases. Arrow keys, Home and End move between marks; touch dragging inspects and lifting pins. Reduced motion skips decorative animation while preserving inspection feedback.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 340px. Dense data may expand within the scrollable viewport.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `members` (`array-of-text key of Row`): Nonempty array of distinct set names defining one exclusive intersection.
- `value` (`numeric key of Row`): Nonnegative numeric measurement. Null or undefined is missing.
- `sort` (`'value' | 'input'`): Sort by descending size (default) or keep input order. Default value.
- `aggregate` (`'sum' | 'mean' | 'max'`): Fallback resting summary. A family-defined summary (such as located point count, hierarchy total, or mean signed value) takes precedence. Use headline to override that summary.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Marker beside each group label, where a group legend is present. Defaults to square.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Layout for the group legend where the data produces groups. False hides it; defaults to tiles.
## Horizon folds: `HorizonFoldsCard`
Signed time series fold into compact bands so many patterns can be read on the same scale. Docs: https://liltui.vercel.app/charts/horizon-folds
```tsx
import { HorizonFoldsCard } from '@lilt-ui/charts';
```
### Complete examples
#### Horizon folds
```tsx
'use client';
import { HorizonFoldsCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const serviceHorizons = [
{ "series": "API", "time": 0, "value": 19 },
{ "series": "API", "time": 1, "value": 28 },
{ "series": "API", "time": 2, "value": 25 },
{ "series": "API", "time": 3, "value": 17 },
{ "series": "API", "time": 4, "value": 14 },
{ "series": "API", "time": 5, "value": 16 },
{ "series": "API", "time": 6, "value": 18 },
{ "series": "API", "time": 7, "value": 11 },
{ "series": "API", "time": 8, "value": -7 },
{ "series": "API", "time": 9, "value": -31 },
{ "series": "API", "time": 10, "value": -48 },
{ "series": "API", "time": 11, "value": -47 },
{ "series": "API", "time": 12, "value": -27 },
{ "series": "API", "time": 13, "value": 4 },
{ "series": "API", "time": 14, "value": 32 },
{ "series": "API", "time": 15, "value": 44 },
{ "series": "API", "time": 16, "value": 38 },
{ "series": "API", "time": 17, "value": 21 },
{ "series": "API", "time": 18, "value": 5 },
{ "series": "API", "time": 19, "value": -3 },
{ "series": "API", "time": 20, "value": -4 },
{ "series": "API", "time": 21, "value": -5 },
{ "series": "API", "time": 22, "value": -13 },
{ "series": "API", "time": 23, "value": -26 },
{ "series": "API", "time": 24, "value": -38 },
{ "series": "Storage", "time": 0, "value": 35 },
{ "series": "Storage", "time": 1, "value": 51 },
{ "series": "Storage", "time": 2, "value": 47 },
{ "series": "Storage", "time": 3, "value": 26 },
{ "series": "Storage", "time": 4, "value": -1 },
{ "series": "Storage", "time": 5, "value": -21 },
{ "series": "Storage", "time": 6, "value": -26 },
{ "series": "Storage", "time": 7, "value": -22 },
{ "series": "Storage", "time": 8, "value": -16 },
{ "series": "Storage", "time": 9, "value": -15 },
{ "series": "Storage", "time": 10, "value": -19 },
{ "series": "Storage", "time": 11, "value": -19 },
{ "series": "Storage", "time": 12, "value": -10 },
{ "series": "Storage", "time": 13, "value": 11 },
{ "series": "Storage", "time": 14, "value": 36 },
{ "series": "Storage", "time": 15, "value": 50 },
{ "series": "Storage", "time": 16, "value": 45 },
{ "series": "Storage", "time": 17, "value": 22 },
{ "series": "Storage", "time": 18, "value": -10 },
{ "series": "Storage", "time": 19, "value": -35 },
{ "series": "Storage", "time": 20, "value": -43 },
{ "series": "Storage", "time": 21, "value": -34 },
{ "series": "Storage", "time": 22, "value": -17 },
{ "series": "Storage", "time": 23, "value": -4 },
{ "series": "Storage", "time": 24, "value": 1 },
{ "series": "Workers", "time": 0, "value": 26 },
{ "series": "Workers", "time": 1, "value": 38 },
{ "series": "Workers", "time": 2, "value": 37 },
{ "series": "Workers", "time": 3, "value": 19 },
{ "series": "Workers", "time": 4, "value": -11 },
{ "series": "Workers", "time": 5, "value": -39 },
{ "series": "Workers", "time": 6, "value": -52 },
{ "series": "Workers", "time": 7, "value": -44 },
{ "series": "Workers", "time": 8, "value": -21 },
{ "series": "Workers", "time": 9, "value": 5 },
{ "series": "Workers", "time": 10, "value": 21 },
{ "series": "Workers", "time": 11, "value": 24 },
{ "series": "Workers", "time": 12, "value": 19 },
{ "series": "Workers", "time": 13, "value": 15 },
{ "series": "Workers", "time": 14, "value": 17 },
{ "series": "Workers", "time": 15, "value": 21 },
{ "series": "Workers", "time": 16, "value": 20 },
{ "series": "Workers", "time": 17, "value": 7 },
{ "series": "Workers", "time": 18, "value": -16 },
{ "series": "Workers", "time": 19, "value": -40 },
{ "series": "Workers", "time": 20, "value": -51 },
{ "series": "Workers", "time": 21, "value": -42 },
{ "series": "Workers", "time": 22, "value": -16 },
{ "series": "Workers", "time": 23, "value": 15 },
{ "series": "Workers", "time": 24, "value": 37 },
{ "series": "Search", "time": 0, "value": 4 },
{ "series": "Search", "time": 1, "value": -1 },
{ "series": "Search", "time": 2, "value": -2 },
{ "series": "Search", "time": 3, "value": -4 },
{ "series": "Search", "time": 4, "value": -15 },
{ "series": "Search", "time": 5, "value": -30 },
{ "series": "Search", "time": 6, "value": -40 },
{ "series": "Search", "time": 7, "value": -36 },
{ "series": "Search", "time": 8, "value": -14 },
{ "series": "Search", "time": 9, "value": 17 },
{ "series": "Search", "time": 10, "value": 43 },
{ "series": "Search", "time": 11, "value": 52 },
{ "series": "Search", "time": 12, "value": 40 },
{ "series": "Search", "time": 13, "value": 16 },
{ "series": "Search", "time": 14, "value": -8 },
{ "series": "Search", "time": 15, "value": -21 },
{ "series": "Search", "time": 16, "value": -22 },
{ "series": "Search", "time": 17, "value": -17 },
{ "series": "Search", "time": 18, "value": -15 },
{ "series": "Search", "time": 19, "value": -19 },
{ "series": "Search", "time": 20, "value": -23 },
{ "series": "Search", "time": 21, "value": -20 },
{ "series": "Search", "time": 22, "value": -4 },
{ "series": "Search", "time": 23, "value": 21 },
{ "series": "Search", "time": 24, "value": 44 },
];
export function Example() {
return (
);
}
```
#### Incomplete observations
Missing readings remain missing while the known observations retain their geometry.
```tsx
'use client';
import { HorizonFoldsCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const horizonsWithGaps = [
{ "series": "API", "time": 0, "value": 19 },
{ "series": "API", "time": 1, "value": 28 },
{ "series": "API", "time": 2, "value": 25 },
{ "series": "API", "time": 3, "value": 17 },
{ "series": "API", "time": 4, "value": null },
{ "series": "API", "time": 5, "value": 16 },
{ "series": "API", "time": 6, "value": 18 },
{ "series": "API", "time": 7, "value": 11 },
{ "series": "API", "time": 8, "value": -7 },
{ "series": "API", "time": 9, "value": -31 },
{ "series": "API", "time": 10, "value": -48 },
{ "series": "API", "time": 11, "value": -47 },
{ "series": "API", "time": 12, "value": -27 },
{ "series": "API", "time": 13, "value": 4 },
{ "series": "API", "time": 14, "value": 32 },
{ "series": "API", "time": 15, "value": 44 },
{ "series": "API", "time": 16, "value": 38 },
{ "series": "API", "time": 17, "value": 21 },
{ "series": "API", "time": 18, "value": 5 },
{ "series": "API", "time": 19, "value": -3 },
{ "series": "API", "time": 20, "value": -4 },
{ "series": "API", "time": 21, "value": null },
{ "series": "API", "time": 22, "value": -13 },
{ "series": "API", "time": 23, "value": -26 },
{ "series": "API", "time": 24, "value": -38 },
{ "series": "Storage", "time": 0, "value": 35 },
{ "series": "Storage", "time": 1, "value": 51 },
{ "series": "Storage", "time": 2, "value": 47 },
{ "series": "Storage", "time": 3, "value": 26 },
{ "series": "Storage", "time": 4, "value": -1 },
{ "series": "Storage", "time": 5, "value": -21 },
{ "series": "Storage", "time": 6, "value": -26 },
{ "series": "Storage", "time": 7, "value": -22 },
{ "series": "Storage", "time": 8, "value": -16 },
{ "series": "Storage", "time": 9, "value": -15 },
{ "series": "Storage", "time": 10, "value": -19 },
{ "series": "Storage", "time": 11, "value": -19 },
{ "series": "Storage", "time": 12, "value": -10 },
{ "series": "Storage", "time": 13, "value": null },
{ "series": "Storage", "time": 14, "value": 36 },
{ "series": "Storage", "time": 15, "value": 50 },
{ "series": "Storage", "time": 16, "value": 45 },
{ "series": "Storage", "time": 17, "value": 22 },
{ "series": "Storage", "time": 18, "value": -10 },
{ "series": "Storage", "time": 19, "value": -35 },
{ "series": "Storage", "time": 20, "value": -43 },
{ "series": "Storage", "time": 21, "value": -34 },
{ "series": "Storage", "time": 22, "value": -17 },
{ "series": "Storage", "time": 23, "value": -4 },
{ "series": "Storage", "time": 24, "value": 1 },
{ "series": "Workers", "time": 0, "value": 26 },
{ "series": "Workers", "time": 1, "value": 38 },
{ "series": "Workers", "time": 2, "value": 37 },
{ "series": "Workers", "time": 3, "value": 19 },
{ "series": "Workers", "time": 4, "value": -11 },
{ "series": "Workers", "time": 5, "value": null },
{ "series": "Workers", "time": 6, "value": -52 },
{ "series": "Workers", "time": 7, "value": -44 },
{ "series": "Workers", "time": 8, "value": -21 },
{ "series": "Workers", "time": 9, "value": 5 },
{ "series": "Workers", "time": 10, "value": 21 },
{ "series": "Workers", "time": 11, "value": 24 },
{ "series": "Workers", "time": 12, "value": 19 },
{ "series": "Workers", "time": 13, "value": 15 },
{ "series": "Workers", "time": 14, "value": 17 },
{ "series": "Workers", "time": 15, "value": 21 },
{ "series": "Workers", "time": 16, "value": 20 },
{ "series": "Workers", "time": 17, "value": 7 },
{ "series": "Workers", "time": 18, "value": -16 },
{ "series": "Workers", "time": 19, "value": -40 },
{ "series": "Workers", "time": 20, "value": -51 },
{ "series": "Workers", "time": 21, "value": -42 },
{ "series": "Workers", "time": 22, "value": null },
{ "series": "Workers", "time": 23, "value": 15 },
{ "series": "Workers", "time": 24, "value": 37 },
{ "series": "Search", "time": 0, "value": 4 },
{ "series": "Search", "time": 1, "value": -1 },
{ "series": "Search", "time": 2, "value": -2 },
{ "series": "Search", "time": 3, "value": -4 },
{ "series": "Search", "time": 4, "value": -15 },
{ "series": "Search", "time": 5, "value": -30 },
{ "series": "Search", "time": 6, "value": -40 },
{ "series": "Search", "time": 7, "value": -36 },
{ "series": "Search", "time": 8, "value": -14 },
{ "series": "Search", "time": 9, "value": 17 },
{ "series": "Search", "time": 10, "value": 43 },
{ "series": "Search", "time": 11, "value": 52 },
{ "series": "Search", "time": 12, "value": 40 },
{ "series": "Search", "time": 13, "value": 16 },
{ "series": "Search", "time": 14, "value": null },
{ "series": "Search", "time": 15, "value": -21 },
{ "series": "Search", "time": 16, "value": -22 },
{ "series": "Search", "time": 17, "value": -17 },
{ "series": "Search", "time": 18, "value": -15 },
{ "series": "Search", "time": 19, "value": -19 },
{ "series": "Search", "time": 20, "value": -23 },
{ "series": "Search", "time": 21, "value": -20 },
{ "series": "Search", "time": 22, "value": -4 },
{ "series": "Search", "time": 23, "value": 21 },
{ "series": "Search", "time": 24, "value": 44 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const serviceHorizons = [
{
"series": "API",
"time": 0,
"value": 19
},
{
"series": "API",
"time": 1,
"value": 28
},
{
"series": "API",
"time": 2,
"value": 25
},
{
"series": "API",
"time": 3,
"value": 17
},
{
"series": "API",
"time": 4,
"value": 14
},
{
"series": "API",
"time": 5,
"value": 16
},
{
"series": "API",
"time": 6,
"value": 18
},
{
"series": "API",
"time": 7,
"value": 11
},
{
"series": "API",
"time": 8,
"value": -7
},
{
"series": "API",
"time": 9,
"value": -31
},
{
"series": "API",
"time": 10,
"value": -48
},
{
"series": "API",
"time": 11,
"value": -47
},
{
"series": "API",
"time": 12,
"value": -27
},
{
"series": "API",
"time": 13,
"value": 4
},
{
"series": "API",
"time": 14,
"value": 32
},
{
"series": "API",
"time": 15,
"value": 44
},
{
"series": "API",
"time": 16,
"value": 38
},
{
"series": "API",
"time": 17,
"value": 21
},
{
"series": "API",
"time": 18,
"value": 5
},
{
"series": "API",
"time": 19,
"value": -3
},
{
"series": "API",
"time": 20,
"value": -4
},
{
"series": "API",
"time": 21,
"value": -5
},
{
"series": "API",
"time": 22,
"value": -13
},
{
"series": "API",
"time": 23,
"value": -26
},
{
"series": "API",
"time": 24,
"value": -38
},
{
"series": "Storage",
"time": 0,
"value": 35
},
{
"series": "Storage",
"time": 1,
"value": 51
},
{
"series": "Storage",
"time": 2,
"value": 47
},
{
"series": "Storage",
"time": 3,
"value": 26
},
{
"series": "Storage",
"time": 4,
"value": -1
},
{
"series": "Storage",
"time": 5,
"value": -21
},
{
"series": "Storage",
"time": 6,
"value": -26
},
{
"series": "Storage",
"time": 7,
"value": -22
},
{
"series": "Storage",
"time": 8,
"value": -16
},
{
"series": "Storage",
"time": 9,
"value": -15
},
{
"series": "Storage",
"time": 10,
"value": -19
},
{
"series": "Storage",
"time": 11,
"value": -19
},
{
"series": "Storage",
"time": 12,
"value": -10
},
{
"series": "Storage",
"time": 13,
"value": 11
},
{
"series": "Storage",
"time": 14,
"value": 36
},
{
"series": "Storage",
"time": 15,
"value": 50
},
{
"series": "Storage",
"time": 16,
"value": 45
},
{
"series": "Storage",
"time": 17,
"value": 22
},
{
"series": "Storage",
"time": 18,
"value": -10
},
{
"series": "Storage",
"time": 19,
"value": -35
},
{
"series": "Storage",
"time": 20,
"value": -43
},
{
"series": "Storage",
"time": 21,
"value": -34
},
{
"series": "Storage",
"time": 22,
"value": -17
},
{
"series": "Storage",
"time": 23,
"value": -4
},
{
"series": "Storage",
"time": 24,
"value": 1
},
{
"series": "Workers",
"time": 0,
"value": 26
},
{
"series": "Workers",
"time": 1,
"value": 38
},
{
"series": "Workers",
"time": 2,
"value": 37
},
{
"series": "Workers",
"time": 3,
"value": 19
},
{
"series": "Workers",
"time": 4,
"value": -11
},
{
"series": "Workers",
"time": 5,
"value": -39
},
{
"series": "Workers",
"time": 6,
"value": -52
},
{
"series": "Workers",
"time": 7,
"value": -44
},
{
"series": "Workers",
"time": 8,
"value": -21
},
{
"series": "Workers",
"time": 9,
"value": 5
},
{
"series": "Workers",
"time": 10,
"value": 21
},
{
"series": "Workers",
"time": 11,
"value": 24
},
{
"series": "Workers",
"time": 12,
"value": 19
},
{
"series": "Workers",
"time": 13,
"value": 15
},
{
"series": "Workers",
"time": 14,
"value": 17
},
{
"series": "Workers",
"time": 15,
"value": 21
},
{
"series": "Workers",
"time": 16,
"value": 20
},
{
"series": "Workers",
"time": 17,
"value": 7
},
{
"series": "Workers",
"time": 18,
"value": -16
},
{
"series": "Workers",
"time": 19,
"value": -40
},
{
"series": "Workers",
"time": 20,
"value": -51
},
{
"series": "Workers",
"time": 21,
"value": -42
},
{
"series": "Workers",
"time": 22,
"value": -16
},
{
"series": "Workers",
"time": 23,
"value": 15
},
{
"series": "Workers",
"time": 24,
"value": 37
},
{
"series": "Search",
"time": 0,
"value": 4
},
{
"series": "Search",
"time": 1,
"value": -1
},
{
"series": "Search",
"time": 2,
"value": -2
},
{
"series": "Search",
"time": 3,
"value": -4
},
{
"series": "Search",
"time": 4,
"value": -15
},
{
"series": "Search",
"time": 5,
"value": -30
},
{
"series": "Search",
"time": 6,
"value": -40
},
{
"series": "Search",
"time": 7,
"value": -36
},
{
"series": "Search",
"time": 8,
"value": -14
},
{
"series": "Search",
"time": 9,
"value": 17
},
{
"series": "Search",
"time": 10,
"value": 43
},
{
"series": "Search",
"time": 11,
"value": 52
},
{
"series": "Search",
"time": 12,
"value": 40
},
{
"series": "Search",
"time": 13,
"value": 16
},
{
"series": "Search",
"time": 14,
"value": -8
},
{
"series": "Search",
"time": 15,
"value": -21
},
{
"series": "Search",
"time": 16,
"value": -22
},
{
"series": "Search",
"time": 17,
"value": -17
},
{
"series": "Search",
"time": 18,
"value": -15
},
{
"series": "Search",
"time": 19,
"value": -19
},
{
"series": "Search",
"time": 20,
"value": -23
},
{
"series": "Search",
"time": 21,
"value": -20
},
{
"series": "Search",
"time": 22,
"value": -4
},
{
"series": "Search",
"time": 23,
"value": 21
},
{
"series": "Search",
"time": 24,
"value": 44
}
];
```
One row per series and numeric time. Samples sort by time within each series. All series share one absolute magnitude scale. Positive values use the first palette color and negative values use the fourth; deeper color represents higher bands. Missing samples break the shape. Inspection reports the original signed value, and the resting headline is the mean of known values.
### Hover
Shaped shimmer, staggered draw and breathe placeholders share the existing opacity exit before the entrance reveal. Refreshes retain accepted data. Hover or focus reads the original observation; click or Enter pins it, and Escape releases. Arrow keys, Home and End move between marks; touch dragging inspects and lifting pins. Reduced motion skips decorative animation while preserving inspection feedback.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 330px. Dense data may expand within the scrollable viewport.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `series` (`text key of Row`): Series label; each series retains one track.
- `time` (`numeric key of Row`): Finite numeric time. Samples are sorted within each series.
- `value` (`numeric key of Row`): Signed numeric measurement. Null or undefined is missing.
- `bands` (`number`): Number of folded magnitude bands, 2 to 5. Default 3.
- `aggregate` (`'sum' | 'mean' | 'max'`): Fallback resting summary. A family-defined summary (such as located point count, hierarchy total, or mean signed value) takes precedence. Use headline to override that summary.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Marker beside each group label, where a group legend is present. Defaults to square.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Layout for the group legend where the data produces groups. False hides it; defaults to tiles.
## Circle archipelago: `CircleArchipelagoCard`
Nested islands of circles reveal a hierarchy while leaf areas keep a common value scale. Docs: https://liltui.vercel.app/charts/circle-archipelago
```tsx
import { CircleArchipelagoCard } from '@lilt-ui/charts';
```
### Complete examples
#### Circle archipelago
```tsx
'use client';
import { CircleArchipelagoCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const spatialHierarchy = [
{ "path": "Product/Platform/API", "value": 42 },
{ "path": "Product/Platform/Storage", "value": 26 },
{ "path": "Product/Experience/Web", "value": 32 },
{ "path": "Product/Experience/Mobile", "value": 24 },
{ "path": "Operations/Support", "value": 29 },
{ "path": "Operations/Success", "value": 18 },
{ "path": "Growth/Acquisition", "value": 34 },
{ "path": "Growth/Retention", "value": 22 },
];
export function Example() {
return (
);
}
```
#### Incomplete observations
Missing readings remain missing while the known observations retain their geometry.
```tsx
'use client';
import { CircleArchipelagoCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const hierarchyWithGaps = [
{ "path": "Product/Platform/API", "value": 42 },
{ "path": "Product/Platform/Storage", "value": 26 },
{ "path": "Product/Experience/Web", "value": null },
{ "path": "Product/Experience/Mobile", "value": 24 },
{ "path": "Operations/Support", "value": 0 },
{ "path": "Operations/Success", "value": 18 },
{ "path": "Growth/Acquisition", "value": 34 },
{ "path": "Growth/Retention", "value": 22 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const spatialHierarchy = [
{
"path": "Product/Platform/API",
"value": 42
},
{
"path": "Product/Platform/Storage",
"value": 26
},
{
"path": "Product/Experience/Web",
"value": 32
},
{
"path": "Product/Experience/Mobile",
"value": 24
},
{
"path": "Operations/Support",
"value": 29
},
{
"path": "Operations/Success",
"value": 18
},
{
"path": "Growth/Acquisition",
"value": 34
},
{
"path": "Growth/Retention",
"value": 22
}
];
```
Use unique leaf-only slash-separated paths and nonnegative values. Every leaf radius uses the square root of its value with one common scale, even across branches. Enclosing circles are grouping boundaries, not total-value bubbles. Missing and zero leaves have no invented area. Deterministic packing keeps siblings separate.
### Hover
Shaped shimmer, staggered draw and breathe placeholders share the existing opacity exit before the entrance reveal. Refreshes retain accepted data. Hover or focus reads the original observation; click or Enter pins it, and Escape releases. Arrow keys, Home and End move between marks; touch dragging inspects and lifting pins. Reduced motion skips decorative animation while preserving inspection feedback.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 380px. Dense data may expand within the scrollable viewport.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `path` (`text key of Row`): Unique leaf path. Separate hierarchy levels with /; do not supply parent-total rows.
- `value` (`numeric key of Row`): Nonnegative numeric measurement. Null or undefined is missing.
- `padding` (`number`): Circle packing gap in square-root value units, 0 to 3. Default 0.7.
- `aggregate` (`'sum' | 'mean' | 'max'`): Fallback resting summary. A family-defined summary (such as located point count, hierarchy total, or mean signed value) takes precedence. Use headline to override that summary.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Marker beside each group label, where a group legend is present. Defaults to square.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Layout for the group legend where the data produces groups. False hides it; defaults to tiles.
## Helix ribbons: `HelixRibbonsCard`
Recurring signals wind upward as ribbons, aligning the same phase across successive cycles. Docs: https://liltui.vercel.app/charts/helix-ribbons
```tsx
import { HelixRibbonsCard } from '@lilt-ui/charts';
```
### Complete examples
#### Helix ribbons
```tsx
'use client';
import { HelixRibbonsCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const cyclicRibbons = [
{ "series": "API", "cycle": 0, "phase": 0, "value": 48 },
{ "series": "API", "cycle": 0, "phase": 0.125, "value": 59 },
{ "series": "API", "cycle": 0, "phase": 0.25, "value": 59 },
{ "series": "API", "cycle": 0, "phase": 0.375, "value": 52 },
{ "series": "API", "cycle": 0, "phase": 0.5, "value": 42 },
{ "series": "API", "cycle": 0, "phase": 0.625, "value": 34 },
{ "series": "API", "cycle": 0, "phase": 0.75, "value": 29 },
{ "series": "API", "cycle": 0, "phase": 0.875, "value": 25 },
{ "series": "API", "cycle": 1, "phase": 0, "value": 22 },
{ "series": "API", "cycle": 1, "phase": 0.125, "value": 24 },
{ "series": "API", "cycle": 1, "phase": 0.25, "value": 32 },
{ "series": "API", "cycle": 1, "phase": 0.375, "value": 46 },
{ "series": "API", "cycle": 1, "phase": 0.5, "value": 60 },
{ "series": "API", "cycle": 1, "phase": 0.625, "value": 66 },
{ "series": "API", "cycle": 1, "phase": 0.75, "value": 59 },
{ "series": "API", "cycle": 1, "phase": 0.875, "value": 40 },
{ "series": "API", "cycle": 2, "phase": 0, "value": 18 },
{ "series": "API", "cycle": 2, "phase": 0.125, "value": 5 },
{ "series": "API", "cycle": 2, "phase": 0.25, "value": 8 },
{ "series": "API", "cycle": 2, "phase": 0.375, "value": 27 },
{ "series": "API", "cycle": 2, "phase": 0.5, "value": 50 },
{ "series": "API", "cycle": 2, "phase": 0.625, "value": 66 },
{ "series": "API", "cycle": 2, "phase": 0.75, "value": 68 },
{ "series": "API", "cycle": 2, "phase": 0.875, "value": 55 },
{ "series": "API", "cycle": 3, "phase": 0, "value": 37 },
{ "series": "API", "cycle": 3, "phase": 0.125, "value": 22 },
{ "series": "API", "cycle": 3, "phase": 0.25, "value": 17 },
{ "series": "API", "cycle": 3, "phase": 0.375, "value": 21 },
{ "series": "API", "cycle": 3, "phase": 0.5, "value": 29 },
{ "series": "API", "cycle": 3, "phase": 0.625, "value": 37 },
{ "series": "API", "cycle": 3, "phase": 0.75, "value": 43 },
{ "series": "API", "cycle": 3, "phase": 0.875, "value": 49 },
{ "series": "Workers", "cycle": 0, "phase": 0, "value": 64 },
{ "series": "Workers", "cycle": 0, "phase": 0.125, "value": 72 },
{ "series": "Workers", "cycle": 0, "phase": 0.25, "value": 63 },
{ "series": "Workers", "cycle": 0, "phase": 0.375, "value": 42 },
{ "series": "Workers", "cycle": 0, "phase": 0.5, "value": 20 },
{ "series": "Workers", "cycle": 0, "phase": 0.625, "value": 8 },
{ "series": "Workers", "cycle": 0, "phase": 0.75, "value": 11 },
{ "series": "Workers", "cycle": 0, "phase": 0.875, "value": 26 },
{ "series": "Workers", "cycle": 1, "phase": 0, "value": 44 },
{ "series": "Workers", "cycle": 1, "phase": 0.125, "value": 56 },
{ "series": "Workers", "cycle": 1, "phase": 0.25, "value": 58 },
{ "series": "Workers", "cycle": 1, "phase": 0.375, "value": 53 },
{ "series": "Workers", "cycle": 1, "phase": 0.5, "value": 45 },
{ "series": "Workers", "cycle": 1, "phase": 0.625, "value": 38 },
{ "series": "Workers", "cycle": 1, "phase": 0.75, "value": 31 },
{ "series": "Workers", "cycle": 1, "phase": 0.875, "value": 26 },
{ "series": "Workers", "cycle": 2, "phase": 0, "value": 21 },
{ "series": "Workers", "cycle": 2, "phase": 0.125, "value": 21 },
{ "series": "Workers", "cycle": 2, "phase": 0.25, "value": 28 },
{ "series": "Workers", "cycle": 2, "phase": 0.375, "value": 42 },
{ "series": "Workers", "cycle": 2, "phase": 0.5, "value": 58 },
{ "series": "Workers", "cycle": 2, "phase": 0.625, "value": 67 },
{ "series": "Workers", "cycle": 2, "phase": 0.75, "value": 62 },
{ "series": "Workers", "cycle": 2, "phase": 0.875, "value": 44 },
{ "series": "Workers", "cycle": 3, "phase": 0, "value": 22 },
{ "series": "Workers", "cycle": 3, "phase": 0.125, "value": 6 },
{ "series": "Workers", "cycle": 3, "phase": 0.25, "value": 6 },
{ "series": "Workers", "cycle": 3, "phase": 0.375, "value": 22 },
{ "series": "Workers", "cycle": 3, "phase": 0.5, "value": 46 },
{ "series": "Workers", "cycle": 3, "phase": 0.625, "value": 64 },
{ "series": "Workers", "cycle": 3, "phase": 0.75, "value": 68 },
{ "series": "Workers", "cycle": 3, "phase": 0.875, "value": 58 },
{ "series": "Search", "cycle": 0, "phase": 0, "value": 56 },
{ "series": "Search", "cycle": 0, "phase": 0.125, "value": 54 },
{ "series": "Search", "cycle": 0, "phase": 0.25, "value": 44 },
{ "series": "Search", "cycle": 0, "phase": 0.375, "value": 29 },
{ "series": "Search", "cycle": 0, "phase": 0.5, "value": 14 },
{ "series": "Search", "cycle": 0, "phase": 0.625, "value": 9 },
{ "series": "Search", "cycle": 0, "phase": 0.75, "value": 18 },
{ "series": "Search", "cycle": 0, "phase": 0.875, "value": 39 },
{ "series": "Search", "cycle": 1, "phase": 0, "value": 61 },
{ "series": "Search", "cycle": 1, "phase": 0.125, "value": 72 },
{ "series": "Search", "cycle": 1, "phase": 0.25, "value": 66 },
{ "series": "Search", "cycle": 1, "phase": 0.375, "value": 47 },
{ "series": "Search", "cycle": 1, "phase": 0.5, "value": 24 },
{ "series": "Search", "cycle": 1, "phase": 0.625, "value": 10 },
{ "series": "Search", "cycle": 1, "phase": 0.75, "value": 10 },
{ "series": "Search", "cycle": 1, "phase": 0.875, "value": 23 },
{ "series": "Search", "cycle": 2, "phase": 0, "value": 40 },
{ "series": "Search", "cycle": 2, "phase": 0.125, "value": 53 },
{ "series": "Search", "cycle": 2, "phase": 0.25, "value": 57 },
{ "series": "Search", "cycle": 2, "phase": 0.375, "value": 54 },
{ "series": "Search", "cycle": 2, "phase": 0.5, "value": 47 },
{ "series": "Search", "cycle": 2, "phase": 0.625, "value": 41 },
{ "series": "Search", "cycle": 2, "phase": 0.75, "value": 34 },
{ "series": "Search", "cycle": 2, "phase": 0.875, "value": 28 },
{ "series": "Search", "cycle": 3, "phase": 0, "value": 21 },
{ "series": "Search", "cycle": 3, "phase": 0.125, "value": 19 },
{ "series": "Search", "cycle": 3, "phase": 0.25, "value": 25 },
{ "series": "Search", "cycle": 3, "phase": 0.375, "value": 38 },
{ "series": "Search", "cycle": 3, "phase": 0.5, "value": 56 },
{ "series": "Search", "cycle": 3, "phase": 0.625, "value": 67 },
{ "series": "Search", "cycle": 3, "phase": 0.75, "value": 65 },
{ "series": "Search", "cycle": 3, "phase": 0.875, "value": 49 },
];
export function Example() {
return (
);
}
```
#### Incomplete observations
Missing readings remain missing while the known observations retain their geometry.
```tsx
'use client';
import { HelixRibbonsCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const ribbonsWithGaps = [
{ "series": "API", "cycle": 0, "phase": 0, "value": 48 },
{ "series": "API", "cycle": 0, "phase": 0.125, "value": 59 },
{ "series": "API", "cycle": 0, "phase": 0.25, "value": 59 },
{ "series": "API", "cycle": 0, "phase": 0.375, "value": 52 },
{ "series": "API", "cycle": 0, "phase": 0.5, "value": 42 },
{ "series": "API", "cycle": 0, "phase": 0.625, "value": null },
{ "series": "API", "cycle": 0, "phase": 0.75, "value": 29 },
{ "series": "API", "cycle": 0, "phase": 0.875, "value": 25 },
{ "series": "API", "cycle": 1, "phase": 0, "value": 22 },
{ "series": "API", "cycle": 1, "phase": 0.125, "value": 24 },
{ "series": "API", "cycle": 1, "phase": 0.25, "value": 32 },
{ "series": "API", "cycle": 1, "phase": 0.375, "value": 46 },
{ "series": "API", "cycle": 1, "phase": 0.5, "value": 60 },
{ "series": "API", "cycle": 1, "phase": 0.625, "value": 66 },
{ "series": "API", "cycle": 1, "phase": 0.75, "value": 59 },
{ "series": "API", "cycle": 1, "phase": 0.875, "value": 40 },
{ "series": "API", "cycle": 2, "phase": 0, "value": 18 },
{ "series": "API", "cycle": 2, "phase": 0.125, "value": 5 },
{ "series": "API", "cycle": 2, "phase": 0.25, "value": null },
{ "series": "API", "cycle": 2, "phase": 0.375, "value": 27 },
{ "series": "API", "cycle": 2, "phase": 0.5, "value": 50 },
{ "series": "API", "cycle": 2, "phase": 0.625, "value": 66 },
{ "series": "API", "cycle": 2, "phase": 0.75, "value": 68 },
{ "series": "API", "cycle": 2, "phase": 0.875, "value": 55 },
{ "series": "API", "cycle": 3, "phase": 0, "value": 37 },
{ "series": "API", "cycle": 3, "phase": 0.125, "value": 22 },
{ "series": "API", "cycle": 3, "phase": 0.25, "value": 17 },
{ "series": "API", "cycle": 3, "phase": 0.375, "value": 21 },
{ "series": "API", "cycle": 3, "phase": 0.5, "value": 29 },
{ "series": "API", "cycle": 3, "phase": 0.625, "value": 37 },
{ "series": "API", "cycle": 3, "phase": 0.75, "value": 43 },
{ "series": "API", "cycle": 3, "phase": 0.875, "value": null },
{ "series": "Workers", "cycle": 0, "phase": 0, "value": 64 },
{ "series": "Workers", "cycle": 0, "phase": 0.125, "value": 72 },
{ "series": "Workers", "cycle": 0, "phase": 0.25, "value": 63 },
{ "series": "Workers", "cycle": 0, "phase": 0.375, "value": 42 },
{ "series": "Workers", "cycle": 0, "phase": 0.5, "value": 20 },
{ "series": "Workers", "cycle": 0, "phase": 0.625, "value": 8 },
{ "series": "Workers", "cycle": 0, "phase": 0.75, "value": 11 },
{ "series": "Workers", "cycle": 0, "phase": 0.875, "value": 26 },
{ "series": "Workers", "cycle": 1, "phase": 0, "value": 44 },
{ "series": "Workers", "cycle": 1, "phase": 0.125, "value": 56 },
{ "series": "Workers", "cycle": 1, "phase": 0.25, "value": 58 },
{ "series": "Workers", "cycle": 1, "phase": 0.375, "value": 53 },
{ "series": "Workers", "cycle": 1, "phase": 0.5, "value": null },
{ "series": "Workers", "cycle": 1, "phase": 0.625, "value": 38 },
{ "series": "Workers", "cycle": 1, "phase": 0.75, "value": 31 },
{ "series": "Workers", "cycle": 1, "phase": 0.875, "value": 26 },
{ "series": "Workers", "cycle": 2, "phase": 0, "value": 21 },
{ "series": "Workers", "cycle": 2, "phase": 0.125, "value": 21 },
{ "series": "Workers", "cycle": 2, "phase": 0.25, "value": 28 },
{ "series": "Workers", "cycle": 2, "phase": 0.375, "value": 42 },
{ "series": "Workers", "cycle": 2, "phase": 0.5, "value": 58 },
{ "series": "Workers", "cycle": 2, "phase": 0.625, "value": 67 },
{ "series": "Workers", "cycle": 2, "phase": 0.75, "value": 62 },
{ "series": "Workers", "cycle": 2, "phase": 0.875, "value": 44 },
{ "series": "Workers", "cycle": 3, "phase": 0, "value": 22 },
{ "series": "Workers", "cycle": 3, "phase": 0.125, "value": null },
{ "series": "Workers", "cycle": 3, "phase": 0.25, "value": 6 },
{ "series": "Workers", "cycle": 3, "phase": 0.375, "value": 22 },
{ "series": "Workers", "cycle": 3, "phase": 0.5, "value": 46 },
{ "series": "Workers", "cycle": 3, "phase": 0.625, "value": 64 },
{ "series": "Workers", "cycle": 3, "phase": 0.75, "value": 68 },
{ "series": "Workers", "cycle": 3, "phase": 0.875, "value": 58 },
{ "series": "Search", "cycle": 0, "phase": 0, "value": 56 },
{ "series": "Search", "cycle": 0, "phase": 0.125, "value": 54 },
{ "series": "Search", "cycle": 0, "phase": 0.25, "value": 44 },
{ "series": "Search", "cycle": 0, "phase": 0.375, "value": 29 },
{ "series": "Search", "cycle": 0, "phase": 0.5, "value": 14 },
{ "series": "Search", "cycle": 0, "phase": 0.625, "value": 9 },
{ "series": "Search", "cycle": 0, "phase": 0.75, "value": null },
{ "series": "Search", "cycle": 0, "phase": 0.875, "value": 39 },
{ "series": "Search", "cycle": 1, "phase": 0, "value": 61 },
{ "series": "Search", "cycle": 1, "phase": 0.125, "value": 72 },
{ "series": "Search", "cycle": 1, "phase": 0.25, "value": 66 },
{ "series": "Search", "cycle": 1, "phase": 0.375, "value": 47 },
{ "series": "Search", "cycle": 1, "phase": 0.5, "value": 24 },
{ "series": "Search", "cycle": 1, "phase": 0.625, "value": 10 },
{ "series": "Search", "cycle": 1, "phase": 0.75, "value": 10 },
{ "series": "Search", "cycle": 1, "phase": 0.875, "value": 23 },
{ "series": "Search", "cycle": 2, "phase": 0, "value": 40 },
{ "series": "Search", "cycle": 2, "phase": 0.125, "value": 53 },
{ "series": "Search", "cycle": 2, "phase": 0.25, "value": 57 },
{ "series": "Search", "cycle": 2, "phase": 0.375, "value": null },
{ "series": "Search", "cycle": 2, "phase": 0.5, "value": 47 },
{ "series": "Search", "cycle": 2, "phase": 0.625, "value": 41 },
{ "series": "Search", "cycle": 2, "phase": 0.75, "value": 34 },
{ "series": "Search", "cycle": 2, "phase": 0.875, "value": 28 },
{ "series": "Search", "cycle": 3, "phase": 0, "value": 21 },
{ "series": "Search", "cycle": 3, "phase": 0.125, "value": 19 },
{ "series": "Search", "cycle": 3, "phase": 0.25, "value": 25 },
{ "series": "Search", "cycle": 3, "phase": 0.375, "value": 38 },
{ "series": "Search", "cycle": 3, "phase": 0.5, "value": 56 },
{ "series": "Search", "cycle": 3, "phase": 0.625, "value": 67 },
{ "series": "Search", "cycle": 3, "phase": 0.75, "value": 65 },
{ "series": "Search", "cycle": 3, "phase": 0.875, "value": 49 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const cyclicRibbons = [
{
"series": "API",
"cycle": 0,
"phase": 0,
"value": 48
},
{
"series": "API",
"cycle": 0,
"phase": 0.125,
"value": 59
},
{
"series": "API",
"cycle": 0,
"phase": 0.25,
"value": 59
},
{
"series": "API",
"cycle": 0,
"phase": 0.375,
"value": 52
},
{
"series": "API",
"cycle": 0,
"phase": 0.5,
"value": 42
},
{
"series": "API",
"cycle": 0,
"phase": 0.625,
"value": 34
},
{
"series": "API",
"cycle": 0,
"phase": 0.75,
"value": 29
},
{
"series": "API",
"cycle": 0,
"phase": 0.875,
"value": 25
},
{
"series": "API",
"cycle": 1,
"phase": 0,
"value": 22
},
{
"series": "API",
"cycle": 1,
"phase": 0.125,
"value": 24
},
{
"series": "API",
"cycle": 1,
"phase": 0.25,
"value": 32
},
{
"series": "API",
"cycle": 1,
"phase": 0.375,
"value": 46
},
{
"series": "API",
"cycle": 1,
"phase": 0.5,
"value": 60
},
{
"series": "API",
"cycle": 1,
"phase": 0.625,
"value": 66
},
{
"series": "API",
"cycle": 1,
"phase": 0.75,
"value": 59
},
{
"series": "API",
"cycle": 1,
"phase": 0.875,
"value": 40
},
{
"series": "API",
"cycle": 2,
"phase": 0,
"value": 18
},
{
"series": "API",
"cycle": 2,
"phase": 0.125,
"value": 5
},
{
"series": "API",
"cycle": 2,
"phase": 0.25,
"value": 8
},
{
"series": "API",
"cycle": 2,
"phase": 0.375,
"value": 27
},
{
"series": "API",
"cycle": 2,
"phase": 0.5,
"value": 50
},
{
"series": "API",
"cycle": 2,
"phase": 0.625,
"value": 66
},
{
"series": "API",
"cycle": 2,
"phase": 0.75,
"value": 68
},
{
"series": "API",
"cycle": 2,
"phase": 0.875,
"value": 55
},
{
"series": "API",
"cycle": 3,
"phase": 0,
"value": 37
},
{
"series": "API",
"cycle": 3,
"phase": 0.125,
"value": 22
},
{
"series": "API",
"cycle": 3,
"phase": 0.25,
"value": 17
},
{
"series": "API",
"cycle": 3,
"phase": 0.375,
"value": 21
},
{
"series": "API",
"cycle": 3,
"phase": 0.5,
"value": 29
},
{
"series": "API",
"cycle": 3,
"phase": 0.625,
"value": 37
},
{
"series": "API",
"cycle": 3,
"phase": 0.75,
"value": 43
},
{
"series": "API",
"cycle": 3,
"phase": 0.875,
"value": 49
},
{
"series": "Workers",
"cycle": 0,
"phase": 0,
"value": 64
},
{
"series": "Workers",
"cycle": 0,
"phase": 0.125,
"value": 72
},
{
"series": "Workers",
"cycle": 0,
"phase": 0.25,
"value": 63
},
{
"series": "Workers",
"cycle": 0,
"phase": 0.375,
"value": 42
},
{
"series": "Workers",
"cycle": 0,
"phase": 0.5,
"value": 20
},
{
"series": "Workers",
"cycle": 0,
"phase": 0.625,
"value": 8
},
{
"series": "Workers",
"cycle": 0,
"phase": 0.75,
"value": 11
},
{
"series": "Workers",
"cycle": 0,
"phase": 0.875,
"value": 26
},
{
"series": "Workers",
"cycle": 1,
"phase": 0,
"value": 44
},
{
"series": "Workers",
"cycle": 1,
"phase": 0.125,
"value": 56
},
{
"series": "Workers",
"cycle": 1,
"phase": 0.25,
"value": 58
},
{
"series": "Workers",
"cycle": 1,
"phase": 0.375,
"value": 53
},
{
"series": "Workers",
"cycle": 1,
"phase": 0.5,
"value": 45
},
{
"series": "Workers",
"cycle": 1,
"phase": 0.625,
"value": 38
},
{
"series": "Workers",
"cycle": 1,
"phase": 0.75,
"value": 31
},
{
"series": "Workers",
"cycle": 1,
"phase": 0.875,
"value": 26
},
{
"series": "Workers",
"cycle": 2,
"phase": 0,
"value": 21
},
{
"series": "Workers",
"cycle": 2,
"phase": 0.125,
"value": 21
},
{
"series": "Workers",
"cycle": 2,
"phase": 0.25,
"value": 28
},
{
"series": "Workers",
"cycle": 2,
"phase": 0.375,
"value": 42
},
{
"series": "Workers",
"cycle": 2,
"phase": 0.5,
"value": 58
},
{
"series": "Workers",
"cycle": 2,
"phase": 0.625,
"value": 67
},
{
"series": "Workers",
"cycle": 2,
"phase": 0.75,
"value": 62
},
{
"series": "Workers",
"cycle": 2,
"phase": 0.875,
"value": 44
},
{
"series": "Workers",
"cycle": 3,
"phase": 0,
"value": 22
},
{
"series": "Workers",
"cycle": 3,
"phase": 0.125,
"value": 6
},
{
"series": "Workers",
"cycle": 3,
"phase": 0.25,
"value": 6
},
{
"series": "Workers",
"cycle": 3,
"phase": 0.375,
"value": 22
},
{
"series": "Workers",
"cycle": 3,
"phase": 0.5,
"value": 46
},
{
"series": "Workers",
"cycle": 3,
"phase": 0.625,
"value": 64
},
{
"series": "Workers",
"cycle": 3,
"phase": 0.75,
"value": 68
},
{
"series": "Workers",
"cycle": 3,
"phase": 0.875,
"value": 58
},
{
"series": "Search",
"cycle": 0,
"phase": 0,
"value": 56
},
{
"series": "Search",
"cycle": 0,
"phase": 0.125,
"value": 54
},
{
"series": "Search",
"cycle": 0,
"phase": 0.25,
"value": 44
},
{
"series": "Search",
"cycle": 0,
"phase": 0.375,
"value": 29
},
{
"series": "Search",
"cycle": 0,
"phase": 0.5,
"value": 14
},
{
"series": "Search",
"cycle": 0,
"phase": 0.625,
"value": 9
},
{
"series": "Search",
"cycle": 0,
"phase": 0.75,
"value": 18
},
{
"series": "Search",
"cycle": 0,
"phase": 0.875,
"value": 39
},
{
"series": "Search",
"cycle": 1,
"phase": 0,
"value": 61
},
{
"series": "Search",
"cycle": 1,
"phase": 0.125,
"value": 72
},
{
"series": "Search",
"cycle": 1,
"phase": 0.25,
"value": 66
},
{
"series": "Search",
"cycle": 1,
"phase": 0.375,
"value": 47
},
{
"series": "Search",
"cycle": 1,
"phase": 0.5,
"value": 24
},
{
"series": "Search",
"cycle": 1,
"phase": 0.625,
"value": 10
},
{
"series": "Search",
"cycle": 1,
"phase": 0.75,
"value": 10
},
{
"series": "Search",
"cycle": 1,
"phase": 0.875,
"value": 23
},
{
"series": "Search",
"cycle": 2,
"phase": 0,
"value": 40
},
{
"series": "Search",
"cycle": 2,
"phase": 0.125,
"value": 53
},
{
"series": "Search",
"cycle": 2,
"phase": 0.25,
"value": 57
},
{
"series": "Search",
"cycle": 2,
"phase": 0.375,
"value": 54
},
{
"series": "Search",
"cycle": 2,
"phase": 0.5,
"value": 47
},
{
"series": "Search",
"cycle": 2,
"phase": 0.625,
"value": 41
},
{
"series": "Search",
"cycle": 2,
"phase": 0.75,
"value": 34
},
{
"series": "Search",
"cycle": 2,
"phase": 0.875,
"value": 28
},
{
"series": "Search",
"cycle": 3,
"phase": 0,
"value": 21
},
{
"series": "Search",
"cycle": 3,
"phase": 0.125,
"value": 19
},
{
"series": "Search",
"cycle": 3,
"phase": 0.25,
"value": 25
},
{
"series": "Search",
"cycle": 3,
"phase": 0.375,
"value": 38
},
{
"series": "Search",
"cycle": 3,
"phase": 0.5,
"value": 56
},
{
"series": "Search",
"cycle": 3,
"phase": 0.625,
"value": 67
},
{
"series": "Search",
"cycle": 3,
"phase": 0.75,
"value": 65
},
{
"series": "Search",
"cycle": 3,
"phase": 0.875,
"value": 49
}
];
```
Supply an integer cycle and a phase from 0 inclusive to 1 exclusive, with nonnegative magnitude. Cycles must span at most 25 consecutive turns. Width interpolates between known samples; null values or gaps larger than maxGap break the ribbon. Concentric lanes separate series without shifting their measured phase. Beads preserve individual samples.
### Hover
Shaped shimmer, staggered draw and breathe placeholders share the existing opacity exit before the entrance reveal. Refreshes retain accepted data. Hover or focus reads the original observation; click or Enter pins it, and Escape releases. Arrow keys, Home and End move between marks; touch dragging inspects and lifting pins. Reduced motion skips decorative animation while preserving inspection feedback.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 390px. Dense data may expand within the scrollable viewport.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `series` (`text key of Row`): Series label; each series retains one track.
- `cycle` (`numeric key of Row`): Safe integer cycle number. A view spans at most 25 consecutive turns.
- `phase` (`numeric key of Row`): Fraction of a cycle, from 0 inclusive to 1 exclusive.
- `value` (`numeric key of Row`): Nonnegative numeric measurement. Null or undefined is missing.
- `yaw` (`number`): Camera rotation around the vertical axis, in degrees from -180 to 180. Default 25.
- `elevation` (`number`): Camera elevation, 10 to 70 degrees. Default 20.
- `thickness` (`number`): Maximum ribbon width, 3 to 26 pixels. Default 13.
- `maxGap` (`number`): Largest gap between samples, measured in cycles, 0.05 to 1. Default 0.3.
- `aggregate` (`'sum' | 'mean' | 'max'`): Fallback resting summary. A family-defined summary (such as located point count, hierarchy total, or mean signed value) takes precedence. Use headline to override that summary.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Marker beside each group label, where a group legend is present. Defaults to square.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Layout for the group legend where the data produces groups. False hides it; defaults to tiles.
## Voxel cloud: `VoxelCloudCard`
A genuine XYZ scatter of lit cubes, with camera rotation and slices through the original z values. Docs: https://liltui.vercel.app/charts/voxel-cloud
```tsx
import { VoxelCloudCard } from '@lilt-ui/charts';
```
### Complete examples
#### Voxel cloud
```tsx
'use client';
import { VoxelCloudCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const spatialCloud = [
{ "name": "Node 1", "x": 22, "y": 37, "z": 30, "value": 12, "group": "Platform", "links": [
"Node 4",
"Node 7",
] },
{ "name": "Node 2", "x": 85, "y": 36, "z": 78, "value": 29, "group": "Experience", "links": [
"Node 5",
"Node 8",
] },
{ "name": "Node 3", "x": 36, "y": 64, "z": 59, "value": 46, "group": "Growth", "links": [
"Node 6",
"Node 9",
] },
{ "name": "Node 4", "x": 29, "y": 30, "z": 43, "value": 63, "group": "Platform", "links": [
"Node 7",
"Node 10",
] },
{ "name": "Node 5", "x": 79, "y": 48, "z": 73, "value": 80, "group": "Experience", "links": [
"Node 8",
"Node 11",
] },
{ "name": "Node 6", "x": 37, "y": 69, "z": 39, "value": 17, "group": "Growth", "links": [
"Node 9",
"Node 12",
] },
{ "name": "Node 7", "x": 33, "y": 16, "z": 17, "value": 34, "group": "Platform", "links": [
"Node 10",
"Node 13",
] },
{ "name": "Node 8", "x": 71, "y": 47, "z": 53, "value": 51, "group": "Experience", "links": [
"Node 11",
"Node 14",
] },
{ "name": "Node 9", "x": 43, "y": 82, "z": 35, "value": 68, "group": "Growth", "links": [
"Node 12",
"Node 15",
] },
{ "name": "Node 10", "x": 34, "y": 14, "z": 30, "value": 85, "group": "Platform", "links": [
"Node 13",
"Node 16",
] },
{ "name": "Node 11", "x": 66, "y": 35, "z": 78, "value": 22, "group": "Experience", "links": [
"Node 14",
"Node 17",
] },
{ "name": "Node 12", "x": 50, "y": 88, "z": 59, "value": 39, "group": "Growth", "links": [
"Node 15",
"Node 18",
] },
{ "name": "Node 13", "x": 29, "y": 25, "z": 43, "value": 56, "group": "Platform", "links": [
"Node 16",
"Node 19",
] },
{ "name": "Node 14", "x": 64, "y": 26, "z": 73, "value": 73, "group": "Experience", "links": [
"Node 17",
"Node 20",
] },
{ "name": "Node 15", "x": 56, "y": 79, "z": 39, "value": 90, "group": "Growth", "links": [
"Node 18",
"Node 21",
] },
{ "name": "Node 16", "x": 23, "y": 36, "z": 17, "value": 27, "group": "Platform", "links": [
"Node 19",
"Node 22",
] },
{ "name": "Node 17", "x": 67, "y": 32, "z": 53, "value": 44, "group": "Experience", "links": [
"Node 20",
"Node 23",
] },
{ "name": "Node 18", "x": 60, "y": 66, "z": 35, "value": 61, "group": "Growth", "links": [
"Node 21",
"Node 24",
] },
{ "name": "Node 19", "x": 16, "y": 33, "z": 31, "value": 78, "group": "Platform", "links": [
"Node 22",
"Node 25",
] },
{ "name": "Node 20", "x": 73, "y": 46, "z": 78, "value": 15, "group": "Experience", "links": [
"Node 23",
"Node 26",
] },
{ "name": "Node 21", "x": 59, "y": 66, "z": 59, "value": 32, "group": "Growth", "links": [
"Node 24",
"Node 27",
] },
{ "name": "Node 22", "x": 11, "y": 20, "z": 43, "value": 49, "group": "Platform", "links": [
"Node 25",
"Node 28",
] },
{ "name": "Node 23", "x": 80, "y": 49, "z": 73, "value": 66, "group": "Experience", "links": [
"Node 26",
"Node 29",
] },
{ "name": "Node 24", "x": 54, "y": 78, "z": 38, "value": 83, "group": "Growth", "links": [
"Node 27",
"Node 30",
] },
{ "name": "Node 25", "x": 10, "y": 13, "z": 17, "value": 20, "group": "Platform", "links": [
"Node 28",
"Node 1",
] },
{ "name": "Node 26", "x": 86, "y": 39, "z": 53, "value": 37, "group": "Experience", "links": [
"Node 29",
"Node 2",
] },
{ "name": "Node 27", "x": 47, "y": 88, "z": 35, "value": 54, "group": "Growth", "links": [
"Node 30",
"Node 3",
] },
{ "name": "Node 28", "x": 14, "y": 21, "z": 31, "value": 71, "group": "Platform", "links": [
"Node 1",
"Node 4",
] },
{ "name": "Node 29", "x": 88, "y": 27, "z": 78, "value": 88, "group": "Experience", "links": [
"Node 2",
"Node 5",
] },
{ "name": "Node 30", "x": 40, "y": 83, "z": 59, "value": 25, "group": "Growth", "links": [
"Node 3",
"Node 6",
] },
];
export function Example() {
return (
);
}
```
#### Incomplete observations
Missing readings remain missing while the known observations retain their geometry.
```tsx
'use client';
import { VoxelCloudCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const cloudWithGaps = [
{ "name": "Node 1", "x": 22, "y": 37, "z": 30, "value": 12, "group": "Platform", "links": [
"Node 4",
"Node 7",
] },
{ "name": "Node 2", "x": 85, "y": 36, "z": 78, "value": 29, "group": "Experience", "links": [
"Node 5",
"Node 8",
] },
{ "name": "Node 3", "x": 36, "y": 64, "z": 59, "value": 46, "group": "Growth", "links": [
"Node 6",
"Node 9",
] },
{ "name": "Node 4", "x": 29, "y": 30, "z": null, "value": 63, "group": "Platform", "links": [
"Node 7",
"Node 10",
] },
{ "name": "Node 5", "x": 79, "y": 48, "z": 73, "value": 80, "group": "Experience", "links": [
"Node 8",
"Node 11",
] },
{ "name": "Node 6", "x": 37, "y": 69, "z": 39, "value": 17, "group": "Growth", "links": [
"Node 9",
"Node 12",
] },
{ "name": "Node 7", "x": 33, "y": 16, "z": 17, "value": null, "group": "Platform", "links": [
"Node 10",
"Node 13",
] },
{ "name": "Node 8", "x": 71, "y": 47, "z": 53, "value": 51, "group": "Experience", "links": [
"Node 11",
"Node 14",
] },
{ "name": "Node 9", "x": 43, "y": 82, "z": 35, "value": 68, "group": "Growth", "links": [
"Node 12",
"Node 15",
] },
{ "name": "Node 10", "x": 34, "y": 14, "z": 30, "value": 85, "group": "Platform", "links": [
"Node 13",
"Node 16",
] },
{ "name": "Node 11", "x": 66, "y": 35, "z": 78, "value": 22, "group": "Experience", "links": [
"Node 14",
"Node 17",
] },
{ "name": "Node 12", "x": 50, "y": 88, "z": 59, "value": 39, "group": "Growth", "links": [
"Node 15",
"Node 18",
] },
{ "name": "Node 13", "x": 29, "y": 25, "z": 43, "value": 56, "group": "Platform", "links": [
"Node 16",
"Node 19",
] },
{ "name": "Node 14", "x": 64, "y": 26, "z": 73, "value": 73, "group": "Experience", "links": [
"Node 17",
"Node 20",
] },
{ "name": "Node 15", "x": 56, "y": 79, "z": 39, "value": 90, "group": "Growth", "links": [
"Node 18",
"Node 21",
] },
{ "name": "Node 16", "x": 23, "y": 36, "z": 17, "value": 27, "group": "Platform", "links": [
"Node 19",
"Node 22",
] },
{ "name": "Node 17", "x": 67, "y": 32, "z": 53, "value": 44, "group": "Experience", "links": [
"Node 20",
"Node 23",
] },
{ "name": "Node 18", "x": 60, "y": 66, "z": 35, "value": 61, "group": "Growth", "links": [
"Node 21",
"Node 24",
] },
{ "name": "Node 19", "x": 16, "y": 33, "z": 31, "value": 78, "group": "Platform", "links": [
"Node 22",
"Node 25",
] },
{ "name": "Node 20", "x": 73, "y": 46, "z": 78, "value": 15, "group": "Experience", "links": [
"Node 23",
"Node 26",
] },
{ "name": "Node 21", "x": 59, "y": 66, "z": 59, "value": 32, "group": "Growth", "links": [
"Node 24",
"Node 27",
] },
{ "name": "Node 22", "x": 11, "y": 20, "z": 43, "value": 49, "group": "Platform", "links": [
"Node 25",
"Node 28",
] },
{ "name": "Node 23", "x": 80, "y": 49, "z": 73, "value": 66, "group": "Experience", "links": [
"Node 26",
"Node 29",
] },
{ "name": "Node 24", "x": 54, "y": 78, "z": 38, "value": 83, "group": "Growth", "links": [
"Node 27",
"Node 30",
] },
{ "name": "Node 25", "x": 10, "y": 13, "z": 17, "value": 20, "group": "Platform", "links": [
"Node 28",
"Node 1",
] },
{ "name": "Node 26", "x": 86, "y": 39, "z": 53, "value": 37, "group": "Experience", "links": [
"Node 29",
"Node 2",
] },
{ "name": "Node 27", "x": 47, "y": 88, "z": 35, "value": 54, "group": "Growth", "links": [
"Node 30",
"Node 3",
] },
{ "name": "Node 28", "x": 14, "y": 21, "z": 31, "value": 71, "group": "Platform", "links": [
"Node 1",
"Node 4",
] },
{ "name": "Node 29", "x": 88, "y": 27, "z": 78, "value": 88, "group": "Experience", "links": [
"Node 2",
"Node 5",
] },
{ "name": "Node 30", "x": 40, "y": 83, "z": 59, "value": 25, "group": "Growth", "links": [
"Node 3",
"Node 6",
] },
];
export function Example() {
return (
);
}
```
#### The middle layer
A slice through z = 35 to 65 preserves the full coordinate domain while exposing the middle of the cloud.
```tsx
'use client';
import { VoxelCloudCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const spatialCloud = [
{ "name": "Node 1", "x": 22, "y": 37, "z": 30, "value": 12, "group": "Platform", "links": [
"Node 4",
"Node 7",
] },
{ "name": "Node 2", "x": 85, "y": 36, "z": 78, "value": 29, "group": "Experience", "links": [
"Node 5",
"Node 8",
] },
{ "name": "Node 3", "x": 36, "y": 64, "z": 59, "value": 46, "group": "Growth", "links": [
"Node 6",
"Node 9",
] },
{ "name": "Node 4", "x": 29, "y": 30, "z": 43, "value": 63, "group": "Platform", "links": [
"Node 7",
"Node 10",
] },
{ "name": "Node 5", "x": 79, "y": 48, "z": 73, "value": 80, "group": "Experience", "links": [
"Node 8",
"Node 11",
] },
{ "name": "Node 6", "x": 37, "y": 69, "z": 39, "value": 17, "group": "Growth", "links": [
"Node 9",
"Node 12",
] },
{ "name": "Node 7", "x": 33, "y": 16, "z": 17, "value": 34, "group": "Platform", "links": [
"Node 10",
"Node 13",
] },
{ "name": "Node 8", "x": 71, "y": 47, "z": 53, "value": 51, "group": "Experience", "links": [
"Node 11",
"Node 14",
] },
{ "name": "Node 9", "x": 43, "y": 82, "z": 35, "value": 68, "group": "Growth", "links": [
"Node 12",
"Node 15",
] },
{ "name": "Node 10", "x": 34, "y": 14, "z": 30, "value": 85, "group": "Platform", "links": [
"Node 13",
"Node 16",
] },
{ "name": "Node 11", "x": 66, "y": 35, "z": 78, "value": 22, "group": "Experience", "links": [
"Node 14",
"Node 17",
] },
{ "name": "Node 12", "x": 50, "y": 88, "z": 59, "value": 39, "group": "Growth", "links": [
"Node 15",
"Node 18",
] },
{ "name": "Node 13", "x": 29, "y": 25, "z": 43, "value": 56, "group": "Platform", "links": [
"Node 16",
"Node 19",
] },
{ "name": "Node 14", "x": 64, "y": 26, "z": 73, "value": 73, "group": "Experience", "links": [
"Node 17",
"Node 20",
] },
{ "name": "Node 15", "x": 56, "y": 79, "z": 39, "value": 90, "group": "Growth", "links": [
"Node 18",
"Node 21",
] },
{ "name": "Node 16", "x": 23, "y": 36, "z": 17, "value": 27, "group": "Platform", "links": [
"Node 19",
"Node 22",
] },
{ "name": "Node 17", "x": 67, "y": 32, "z": 53, "value": 44, "group": "Experience", "links": [
"Node 20",
"Node 23",
] },
{ "name": "Node 18", "x": 60, "y": 66, "z": 35, "value": 61, "group": "Growth", "links": [
"Node 21",
"Node 24",
] },
{ "name": "Node 19", "x": 16, "y": 33, "z": 31, "value": 78, "group": "Platform", "links": [
"Node 22",
"Node 25",
] },
{ "name": "Node 20", "x": 73, "y": 46, "z": 78, "value": 15, "group": "Experience", "links": [
"Node 23",
"Node 26",
] },
{ "name": "Node 21", "x": 59, "y": 66, "z": 59, "value": 32, "group": "Growth", "links": [
"Node 24",
"Node 27",
] },
{ "name": "Node 22", "x": 11, "y": 20, "z": 43, "value": 49, "group": "Platform", "links": [
"Node 25",
"Node 28",
] },
{ "name": "Node 23", "x": 80, "y": 49, "z": 73, "value": 66, "group": "Experience", "links": [
"Node 26",
"Node 29",
] },
{ "name": "Node 24", "x": 54, "y": 78, "z": 38, "value": 83, "group": "Growth", "links": [
"Node 27",
"Node 30",
] },
{ "name": "Node 25", "x": 10, "y": 13, "z": 17, "value": 20, "group": "Platform", "links": [
"Node 28",
"Node 1",
] },
{ "name": "Node 26", "x": 86, "y": 39, "z": 53, "value": 37, "group": "Experience", "links": [
"Node 29",
"Node 2",
] },
{ "name": "Node 27", "x": 47, "y": 88, "z": 35, "value": 54, "group": "Growth", "links": [
"Node 30",
"Node 3",
] },
{ "name": "Node 28", "x": 14, "y": 21, "z": 31, "value": 71, "group": "Platform", "links": [
"Node 1",
"Node 4",
] },
{ "name": "Node 29", "x": 88, "y": 27, "z": 78, "value": 88, "group": "Experience", "links": [
"Node 2",
"Node 5",
] },
{ "name": "Node 30", "x": 40, "y": 83, "z": 59, "value": 25, "group": "Growth", "links": [
"Node 3",
"Node 6",
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const spatialCloud = [
{
"name": "Node 1",
"x": 22,
"y": 37,
"z": 30,
"value": 12,
"group": "Platform",
"links": [
"Node 4",
"Node 7"
]
},
{
"name": "Node 2",
"x": 85,
"y": 36,
"z": 78,
"value": 29,
"group": "Experience",
"links": [
"Node 5",
"Node 8"
]
},
{
"name": "Node 3",
"x": 36,
"y": 64,
"z": 59,
"value": 46,
"group": "Growth",
"links": [
"Node 6",
"Node 9"
]
},
{
"name": "Node 4",
"x": 29,
"y": 30,
"z": 43,
"value": 63,
"group": "Platform",
"links": [
"Node 7",
"Node 10"
]
},
{
"name": "Node 5",
"x": 79,
"y": 48,
"z": 73,
"value": 80,
"group": "Experience",
"links": [
"Node 8",
"Node 11"
]
},
{
"name": "Node 6",
"x": 37,
"y": 69,
"z": 39,
"value": 17,
"group": "Growth",
"links": [
"Node 9",
"Node 12"
]
},
{
"name": "Node 7",
"x": 33,
"y": 16,
"z": 17,
"value": 34,
"group": "Platform",
"links": [
"Node 10",
"Node 13"
]
},
{
"name": "Node 8",
"x": 71,
"y": 47,
"z": 53,
"value": 51,
"group": "Experience",
"links": [
"Node 11",
"Node 14"
]
},
{
"name": "Node 9",
"x": 43,
"y": 82,
"z": 35,
"value": 68,
"group": "Growth",
"links": [
"Node 12",
"Node 15"
]
},
{
"name": "Node 10",
"x": 34,
"y": 14,
"z": 30,
"value": 85,
"group": "Platform",
"links": [
"Node 13",
"Node 16"
]
},
{
"name": "Node 11",
"x": 66,
"y": 35,
"z": 78,
"value": 22,
"group": "Experience",
"links": [
"Node 14",
"Node 17"
]
},
{
"name": "Node 12",
"x": 50,
"y": 88,
"z": 59,
"value": 39,
"group": "Growth",
"links": [
"Node 15",
"Node 18"
]
},
{
"name": "Node 13",
"x": 29,
"y": 25,
"z": 43,
"value": 56,
"group": "Platform",
"links": [
"Node 16",
"Node 19"
]
},
{
"name": "Node 14",
"x": 64,
"y": 26,
"z": 73,
"value": 73,
"group": "Experience",
"links": [
"Node 17",
"Node 20"
]
},
{
"name": "Node 15",
"x": 56,
"y": 79,
"z": 39,
"value": 90,
"group": "Growth",
"links": [
"Node 18",
"Node 21"
]
},
{
"name": "Node 16",
"x": 23,
"y": 36,
"z": 17,
"value": 27,
"group": "Platform",
"links": [
"Node 19",
"Node 22"
]
},
{
"name": "Node 17",
"x": 67,
"y": 32,
"z": 53,
"value": 44,
"group": "Experience",
"links": [
"Node 20",
"Node 23"
]
},
{
"name": "Node 18",
"x": 60,
"y": 66,
"z": 35,
"value": 61,
"group": "Growth",
"links": [
"Node 21",
"Node 24"
]
},
{
"name": "Node 19",
"x": 16,
"y": 33,
"z": 31,
"value": 78,
"group": "Platform",
"links": [
"Node 22",
"Node 25"
]
},
{
"name": "Node 20",
"x": 73,
"y": 46,
"z": 78,
"value": 15,
"group": "Experience",
"links": [
"Node 23",
"Node 26"
]
},
{
"name": "Node 21",
"x": 59,
"y": 66,
"z": 59,
"value": 32,
"group": "Growth",
"links": [
"Node 24",
"Node 27"
]
},
{
"name": "Node 22",
"x": 11,
"y": 20,
"z": 43,
"value": 49,
"group": "Platform",
"links": [
"Node 25",
"Node 28"
]
},
{
"name": "Node 23",
"x": 80,
"y": 49,
"z": 73,
"value": 66,
"group": "Experience",
"links": [
"Node 26",
"Node 29"
]
},
{
"name": "Node 24",
"x": 54,
"y": 78,
"z": 38,
"value": 83,
"group": "Growth",
"links": [
"Node 27",
"Node 30"
]
},
{
"name": "Node 25",
"x": 10,
"y": 13,
"z": 17,
"value": 20,
"group": "Platform",
"links": [
"Node 28",
"Node 1"
]
},
{
"name": "Node 26",
"x": 86,
"y": 39,
"z": 53,
"value": 37,
"group": "Experience",
"links": [
"Node 29",
"Node 2"
]
},
{
"name": "Node 27",
"x": 47,
"y": 88,
"z": 35,
"value": 54,
"group": "Growth",
"links": [
"Node 30",
"Node 3"
]
},
{
"name": "Node 28",
"x": 14,
"y": 21,
"z": 31,
"value": 71,
"group": "Platform",
"links": [
"Node 1",
"Node 4"
]
},
{
"name": "Node 29",
"x": 88,
"y": 27,
"z": 78,
"value": 88,
"group": "Experience",
"links": [
"Node 2",
"Node 5"
]
},
{
"name": "Node 30",
"x": 40,
"y": 83,
"z": 59,
"value": 25,
"group": "Growth",
"links": [
"Node 3",
"Node 6"
]
}
];
```
Supply unique labels, XYZ coordinates and nonnegative magnitude. Each coordinate has an independent linear scale and equal-valued axes are centred. Positive cube volume carries magnitude; zero and missing magnitudes use small distinct inspection markers. Slice bounds are inclusive in original z units and do not rescale the camera. All rows remain in the table, including missing and sliced-out positions. The headline counts visible positioned observations.
### Hover
Shaped shimmer, staggered draw and breathe placeholders share the existing opacity exit before the entrance reveal. Refreshes retain accepted data. Hover or focus reads the original observation; click or Enter pins it, and Escape releases. Arrow keys, Home and End move between marks; touch dragging inspects and lifting pins. Reduced motion skips decorative animation while preserving inspection feedback.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 360px. Dense data may expand within the scrollable viewport.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `label` (`text key of Row`): Unique nonempty observation label, retained through inspection and pinning.
- `x` (`numeric key of Row`): First spatial coordinate on an independent linear scale.
- `y` (`numeric key of Row`): Second spatial coordinate on an independent linear scale.
- `z` (`numeric key of Row`): Third spatial coordinate on an independent linear scale.
- `value` (`numeric key of Row`): Nonnegative numeric measurement. Null or undefined is missing.
- `group` (`text key of Row`): Optional categorical color key.
- `yaw` (`number`): Camera rotation around the vertical axis, in degrees from -180 to 180. Default 35.
- `elevation` (`number`): Camera elevation, 10 to 70 degrees. Default 25.
- `size` (`number`): Maximum cube half-edge or sphere size as a fraction of the normalized plot, 0.025 to 0.18. Default 0.09.
- `slice` (`readonly [number, number]`): Optional inclusive [min, max] filter in original z units. The camera domain remains fixed.
- `aggregate` (`'sum' | 'mean' | 'max'`): Fallback resting summary. A family-defined summary (such as located point count, hierarchy total, or mean signed value) takes precedence. Use headline to override that summary.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Marker beside each group label, where a group legend is present. Defaults to square.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Layout for the group legend where the data produces groups. False hides it; defaults to tiles.
## Arc bridges: `ArcBridgesCard`
Weighted connections arch over a shared baseline, exposing long jumps and local handoffs. Docs: https://liltui.vercel.app/charts/arc-bridges
```tsx
import { ArcBridgesCard } from '@lilt-ui/charts';
```
### Complete examples
#### Workflow handoffs
```tsx
'use client';
import { ArcBridgesCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const teamHandoffs = [
{ "from": "Design", "to": "Build", "count": 84 },
{ "from": "Design", "to": "Research", "count": 26 },
{ "from": "Build", "to": "Review", "count": 68 },
{ "from": "Review", "to": "Design", "count": 32 },
{ "from": "Review", "to": "Launch", "count": 46 },
{ "from": "Research", "to": "Build", "count": 38 },
{ "from": "Launch", "to": "Research", "count": 20 },
];
export function Example() {
return (
);
}
```
#### Incomplete routes
Absent and measured-zero connections remain distinct in the data without drawing false bridges.
```tsx
'use client';
import { ArcBridgesCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const handoffsWithGaps = [
{ "from": "Design", "to": "Build", "count": 84 },
{ "from": "Design", "to": "Research", "count": 26 },
{ "from": "Build", "to": "Review", "count": null },
{ "from": "Review", "to": "Design", "count": 32 },
{ "from": "Review", "to": "Launch", "count": 0 },
{ "from": "Research", "to": "Build", "count": 38 },
{ "from": "Launch", "to": "Research", "count": 20 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const teamHandoffs = [
{ from: 'Design', to: 'Build', count: 84 },
{ from: 'Build', to: 'Review', count: 68 },
];
```
One row per directed pair, with nonnegative weight. Nodes retain first-seen order; arch height reflects separation along that ordering, while thickness carries flow. Color identifies the source. Reverse links use a lower arch so both directions can be inspected. Legend totals count outgoing flows only. Missing and zero links remain in the accessible table without a bridge; self-links and duplicate pairs are rejected.
### Hover
Bridges draw across their silhouettes in sequence. Hover or focus to read the original observation in the headline. Click or press Enter to pin; Escape releases. Arrow keys, Home, and End move between marks. Touch dragging inspects and lifting pins. Loading uses shaped shimmer, staggered draw, or breathe placeholders, holds through its opacity exit, then reveals the data. Refreshes retain accepted data. Reduced motion keeps inspection feedback and skips decorative animation.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 300. Dense data can expand or scroll to preserve geometry.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `source` (`text key of Row`): Source node; nodes retain first-seen order.
- `target` (`text key of Row`): Destination node. Must differ from source.
- `value` (`numeric key of Row`): Nonnegative flow. Null is missing; zero has no ribbon but remains in the accessible table.
- `rise` (`number`): Maximum arch height as a fraction of plot height, 0.3 to 1, default 0.85.
- `thickness` (`number`): Maximum bridge width, 4 to 28 pixels, default 18.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Rounded-square legend with group inspection and pinning. Defaults to tiles; false removes it.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
- `legendSwatch` (`'square' | 'dot' | 'line'`): Marker beside each group label, where a group legend is present. Defaults to square.
## Terrain: `TerrainCard`
A grid of readings as a lit landscape, so peaks and quiet valleys read at a glance. Docs: https://liltui.vercel.app/charts/terrain
```tsx
import { TerrainCard } from '@lilt-ui/charts';
```
### Complete examples
#### Server load
```tsx
'use client';
import { TerrainCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const serverLoad = [
{ "day": "Mon", "hour": "00:00", "load": 12 },
{ "day": "Mon", "hour": "02:00", "load": 12 },
{ "day": "Mon", "hour": "04:00", "load": 13 },
{ "day": "Mon", "hour": "06:00", "load": 18 },
{ "day": "Mon", "hour": "08:00", "load": 31 },
{ "day": "Mon", "hour": "10:00", "load": 56 },
{ "day": "Mon", "hour": "12:00", "load": 78 },
{ "day": "Mon", "hour": "14:00", "load": 78 },
{ "day": "Mon", "hour": "16:00", "load": 56 },
{ "day": "Mon", "hour": "18:00", "load": 31 },
{ "day": "Mon", "hour": "20:00", "load": 18 },
{ "day": "Mon", "hour": "22:00", "load": 13 },
{ "day": "Tue", "hour": "00:00", "load": 12 },
{ "day": "Tue", "hour": "02:00", "load": 12 },
{ "day": "Tue", "hour": "04:00", "load": 13 },
{ "day": "Tue", "hour": "06:00", "load": 18 },
{ "day": "Tue", "hour": "08:00", "load": 31 },
{ "day": "Tue", "hour": "10:00", "load": 56 },
{ "day": "Tue", "hour": "12:00", "load": 78 },
{ "day": "Tue", "hour": "14:00", "load": 78 },
{ "day": "Tue", "hour": "16:00", "load": 56 },
{ "day": "Tue", "hour": "18:00", "load": 31 },
{ "day": "Tue", "hour": "20:00", "load": 18 },
{ "day": "Tue", "hour": "22:00", "load": 13 },
{ "day": "Wed", "hour": "00:00", "load": 12 },
{ "day": "Wed", "hour": "02:00", "load": 12 },
{ "day": "Wed", "hour": "04:00", "load": 14 },
{ "day": "Wed", "hour": "06:00", "load": 27 },
{ "day": "Wed", "hour": "08:00", "load": 49 },
{ "day": "Wed", "hour": "10:00", "load": 65 },
{ "day": "Wed", "hour": "12:00", "load": 80 },
{ "day": "Wed", "hour": "14:00", "load": 79 },
{ "day": "Wed", "hour": "16:00", "load": 56 },
{ "day": "Wed", "hour": "18:00", "load": 31 },
{ "day": "Wed", "hour": "20:00", "load": 18 },
{ "day": "Wed", "hour": "22:00", "load": 13 },
{ "day": "Thu", "hour": "00:00", "load": 12 },
{ "day": "Thu", "hour": "02:00", "load": 12 },
{ "day": "Thu", "hour": "04:00", "load": 13 },
{ "day": "Thu", "hour": "06:00", "load": 18 },
{ "day": "Thu", "hour": "08:00", "load": 31 },
{ "day": "Thu", "hour": "10:00", "load": 56 },
{ "day": "Thu", "hour": "12:00", "load": 78 },
{ "day": "Thu", "hour": "14:00", "load": 78 },
{ "day": "Thu", "hour": "16:00", "load": 56 },
{ "day": "Thu", "hour": "18:00", "load": 31 },
{ "day": "Thu", "hour": "20:00", "load": 18 },
{ "day": "Thu", "hour": "22:00", "load": 13 },
{ "day": "Fri", "hour": "00:00", "load": 12 },
{ "day": "Fri", "hour": "02:00", "load": 12 },
{ "day": "Fri", "hour": "04:00", "load": 13 },
{ "day": "Fri", "hour": "06:00", "load": 18 },
{ "day": "Fri", "hour": "08:00", "load": 31 },
{ "day": "Fri", "hour": "10:00", "load": 56 },
{ "day": "Fri", "hour": "12:00", "load": 78 },
{ "day": "Fri", "hour": "14:00", "load": 78 },
{ "day": "Fri", "hour": "16:00", "load": 56 },
{ "day": "Fri", "hour": "18:00", "load": 31 },
{ "day": "Fri", "hour": "20:00", "load": 18 },
{ "day": "Fri", "hour": "22:00", "load": 13 },
{ "day": "Sat", "hour": "00:00", "load": 12 },
{ "day": "Sat", "hour": "02:00", "load": 12 },
{ "day": "Sat", "hour": "04:00", "load": 13 },
{ "day": "Sat", "hour": "06:00", "load": 15 },
{ "day": "Sat", "hour": "08:00", "load": 21 },
{ "day": "Sat", "hour": "10:00", "load": 33 },
{ "day": "Sat", "hour": "12:00", "load": 44 },
{ "day": "Sat", "hour": "14:00", "load": 44 },
{ "day": "Sat", "hour": "16:00", "load": 33 },
{ "day": "Sat", "hour": "18:00", "load": 21 },
{ "day": "Sat", "hour": "20:00", "load": 15 },
{ "day": "Sat", "hour": "22:00", "load": 13 },
{ "day": "Sun", "hour": "00:00", "load": 12 },
{ "day": "Sun", "hour": "02:00", "load": 12 },
{ "day": "Sun", "hour": "04:00", "load": 13 },
{ "day": "Sun", "hour": "06:00", "load": 15 },
{ "day": "Sun", "hour": "08:00", "load": 21 },
{ "day": "Sun", "hour": "10:00", "load": 33 },
{ "day": "Sun", "hour": "12:00", "load": 44 },
{ "day": "Sun", "hour": "14:00", "load": 44 },
{ "day": "Sun", "hour": "16:00", "load": 33 },
{ "day": "Sun", "hour": "18:00", "load": 21 },
{ "day": "Sun", "hour": "20:00", "load": 15 },
{ "day": "Sun", "hour": "22:00", "load": 13 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const serverLoad = [
{ day: 'Mon', hour: '00:00', load: 12 },
{ day: 'Mon', hour: '02:00', load: 14 },
// …one row per day and hour
];
```
One row per x and y pair, at least two of each. The surface passes exactly through every reading and is smoothed between them; smoothing sets how many samples sit between neighbours. A missing reading sits on the floor and reads as no data. Duplicate pairs are rejected.
### Hover
Hover or focus a reading to drop a pin onto the surface and read it in the headline. Nearer readings win where pins overlap. Click or press Enter to pin; Escape releases. Arrow keys walk the grid. The surface lifts from a flat floor on load, back to front; reduced motion shows it settled.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 320px. Dense data may expand within the scrollable viewport.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `x` (`text key of Row`): Columns, running away to the right.
- `y` (`text key of Row`): Rows, coming toward the viewer.
- `value` (`numeric key of Row`): Surface height, color, and headline.
- `rise` (`number`): How many cell lengths the highest value rises, default 3.
- `smoothing` (`number`): Surface samples between neighbouring readings, 1 to 6, default 4.
- `domain` (`[number, number]`): Fixed value domain that must contain every value. Defaults to zero through the largest.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Hex city: `HexCityCard`
Every store, team, or product as a hexagonal tower, so the biggest stands tall in the middle. Docs: https://liltui.vercel.app/charts/hex-city
```tsx
import { HexCityCard } from '@lilt-ui/charts';
```
### Complete examples
#### Store revenue
```tsx
'use client';
import { HexCityCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const storeRevenue = [
{ "store": "Soho", "region": "London", "revenue": 98 },
{ "store": "Shoreditch", "region": "London", "revenue": 76 },
{ "store": "Camden", "region": "London", "revenue": 61 },
{ "store": "Brixton", "region": "London", "revenue": 44 },
{ "store": "Mitte", "region": "Berlin", "revenue": 83 },
{ "store": "Kreuzberg", "region": "Berlin", "revenue": 69 },
{ "store": "Neukölln", "region": "Berlin", "revenue": 38 },
{ "store": "Marais", "region": "Paris", "revenue": 88 },
{ "store": "Pigalle", "region": "Paris", "revenue": 57 },
{ "store": "Bastille", "region": "Paris", "revenue": 49 },
{ "store": "Belleville", "region": "Paris", "revenue": 31 },
{ "store": "Jordaan", "region": "Amsterdam", "revenue": 64 },
{ "store": "De Pijp", "region": "Amsterdam", "revenue": 52 },
{ "store": "Noord", "region": "Amsterdam", "revenue": 27 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const storeRevenue = [
{ store: 'Soho', region: 'London', revenue: 98 },
{ store: 'Mitte', region: 'Berlin', revenue: 83 },
// …one row per store
];
```
One row per hexagon with a unique label. By default the largest value stands in the middle and the rest spiral outward by size; arrange="order" keeps your row order instead. group colors the towers and adds a legend with the total for each group. Null stays a low slab.
### Hover
Hover or focus a tower to read it in the headline; hit testing follows the hexagon, and nearer towers win where they overlap. The legend highlights a group. Click or press Enter to pin; Escape releases. The city rises from its centre outward on load; reduced motion skips it.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 260. Dense lanes expand to keep every mark visible.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `label` (`text key of Row`): Unique name for each hexagon.
- `value` (`numeric key of Row`): Tower height and headline.
- `group` (`text key of Row`): Colors towers by category and adds the legend.
- `arrange` (`'rank' | 'order'`): Largest in the middle (default) or your row order.
- `rise` (`number`): How many hexagon widths the largest value rises, default 2.
- `gap` (`number`): Space between hexagons as a share of their size, default 0.12.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Group legend layout when group is set. Defaults to tiles.
- `domain` (`[number, number]`): Fixed value domain that must contain every value. Defaults to zero through the largest.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Voxel waffle: `VoxelWaffleCard`
Shares of a whole as a block of cubes you can count, filling from the floor up. Docs: https://liltui.vercel.app/charts/voxel-waffle
```tsx
import { VoxelWaffleCard } from '@lilt-ui/charts';
```
### Complete examples
#### Where the time went
```tsx
'use client';
import { VoxelWaffleCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const teamTime = [
{ "work": "Building", "hours": 412 },
{ "work": "Reviews", "hours": 188 },
{ "work": "Meetings", "hours": 141 },
{ "work": "Support", "hours": 96 },
{ "work": "Planning", "hours": 63 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const teamTime = [
{ work: 'Building', hours: 412 },
{ work: 'Reviews', hours: 188 },
// …one row per category
];
```
One row per category with a nonnegative value. Values become whole cubes that always add up to units (100 by default, so one cube is one percent), using the largest remainder. Categories fill layer by layer from the floor up in row order. Null takes no cubes but stays in the legend and the accessible table.
### Hover
Hover or focus any cube to read its category in the headline; its other cubes stay lit while the rest soften. The legend highlights a category. Click or press Enter to pin; Escape releases. Cubes drop into place layer by layer on load and land with a small settle; reduced motion skips it.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 260. Dense lanes expand to keep every mark visible.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `category` (`text key of Row`): One color per category.
- `value` (`numeric key of Row`): Nonnegative share of the whole.
- `units` (`number`): How many cubes make the whole, default 100.
- `footprint` (`number`): Cubes along each side of a layer, default 5.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): Category legend layout. Defaults to tiles.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Skyline: `SkylineCard`
A year of daily activity stood up in three dimensions, so streaks and busy weeks read as a skyline. Docs: https://liltui.vercel.app/charts/skyline
```tsx
import { SkylineCard } from '@lilt-ui/charts';
```
### Complete examples
#### Contributions
```tsx
'use client';
import { SkylineCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const yearContributions = [
{ "date": "2025-10-08", "commits": 0 },
{ "date": "2025-10-09", "commits": 1 },
{ "date": "2025-10-10", "commits": 2 },
{ "date": "2025-10-11", "commits": 3 },
{ "date": "2025-10-12", "commits": 0 },
{ "date": "2025-10-13", "commits": 0 },
{ "date": "2025-10-14", "commits": 0 },
{ "date": "2025-10-15", "commits": 5 },
{ "date": "2025-10-16", "commits": 2 },
{ "date": "2025-10-17", "commits": 4 },
{ "date": "2025-10-18", "commits": 6 },
{ "date": "2025-10-19", "commits": 7 },
{ "date": "2025-10-20", "commits": 0 },
{ "date": "2025-10-21", "commits": 0 },
{ "date": "2025-10-22", "commits": 5 },
{ "date": "2025-10-23", "commits": 6 },
{ "date": "2025-10-24", "commits": 2 },
{ "date": "2025-10-25", "commits": 2 },
{ "date": "2025-10-26", "commits": 2 },
{ "date": "2025-10-27", "commits": 0 },
{ "date": "2025-10-28", "commits": 0 },
{ "date": "2025-10-29", "commits": 1 },
{ "date": "2025-10-30", "commits": 2 },
{ "date": "2025-10-31", "commits": 3 },
{ "date": "2025-11-01", "commits": 0 },
{ "date": "2025-11-02", "commits": 1 },
{ "date": "2025-11-03", "commits": 0 },
{ "date": "2025-11-04", "commits": 0 },
{ "date": "2025-11-05", "commits": 0 },
{ "date": "2025-11-06", "commits": 1 },
{ "date": "2025-11-07", "commits": 2 },
{ "date": "2025-11-08", "commits": 3 },
{ "date": "2025-11-09", "commits": 0 },
{ "date": "2025-11-10", "commits": 3 },
{ "date": "2025-11-11", "commits": 0 },
{ "date": "2025-11-12", "commits": 3 },
{ "date": "2025-11-13", "commits": 0 },
{ "date": "2025-11-14", "commits": 1 },
{ "date": "2025-11-15", "commits": 2 },
{ "date": "2025-11-16", "commits": 4 },
{ "date": "2025-11-17", "commits": 0 },
{ "date": "2025-11-18", "commits": 0 },
{ "date": "2025-11-19", "commits": 6 },
{ "date": "2025-11-20", "commits": 8 },
{ "date": "2025-11-21", "commits": 6 },
{ "date": "2025-11-22", "commits": 7 },
{ "date": "2025-11-23", "commits": 8 },
{ "date": "2025-11-24", "commits": 0 },
{ "date": "2025-11-25", "commits": 0 },
{ "date": "2025-11-26", "commits": 5 },
{ "date": "2025-11-27", "commits": 5 },
{ "date": "2025-11-28", "commits": 5 },
{ "date": "2025-11-29", "commits": 1 },
{ "date": "2025-11-30", "commits": 2 },
{ "date": "2025-12-01", "commits": 0 },
{ "date": "2025-12-02", "commits": 3 },
{ "date": "2025-12-03", "commits": 0 },
{ "date": "2025-12-04", "commits": 1 },
{ "date": "2025-12-05", "commits": 2 },
{ "date": "2025-12-06", "commits": 3 },
{ "date": "2025-12-07", "commits": 0 },
{ "date": "2025-12-08", "commits": 0 },
{ "date": "2025-12-09", "commits": 0 },
{ "date": "2025-12-10", "commits": 3 },
{ "date": "2025-12-11", "commits": 1 },
{ "date": "2025-12-12", "commits": 2 },
{ "date": "2025-12-13", "commits": 3 },
{ "date": "2025-12-14", "commits": 5 },
{ "date": "2025-12-15", "commits": 0 },
{ "date": "2025-12-16", "commits": 0 },
{ "date": "2025-12-17", "commits": 4 },
{ "date": "2025-12-18", "commits": 5 },
{ "date": "2025-12-19", "commits": 1 },
{ "date": "2025-12-20", "commits": 2 },
{ "date": "2025-12-21", "commits": 2 },
{ "date": "2025-12-22", "commits": 0 },
{ "date": "2025-12-23", "commits": 0 },
{ "date": "2025-12-24", "commits": 1 },
{ "date": "2025-12-25", "commits": 2 },
{ "date": "2025-12-26", "commits": 3 },
{ "date": "2025-12-27", "commits": 0 },
{ "date": "2025-12-28", "commits": 1 },
{ "date": "2025-12-29", "commits": 0 },
{ "date": "2025-12-30", "commits": 0 },
{ "date": "2025-12-31", "commits": 0 },
{ "date": "2026-01-01", "commits": 1 },
{ "date": "2026-01-02", "commits": 2 },
{ "date": "2026-01-03", "commits": 3 },
{ "date": "2026-01-04", "commits": 0 },
{ "date": "2026-01-05", "commits": 0 },
{ "date": "2026-01-06", "commits": 0 },
{ "date": "2026-01-07", "commits": 3 },
{ "date": "2026-01-08", "commits": 0 },
{ "date": "2026-01-09", "commits": 1 },
{ "date": "2026-01-10", "commits": 2 },
{ "date": "2026-01-11", "commits": 3 },
{ "date": "2026-01-12", "commits": 0 },
{ "date": "2026-01-13", "commits": 0 },
{ "date": "2026-01-14", "commits": 6 },
{ "date": "2026-01-15", "commits": 8 },
{ "date": "2026-01-16", "commits": 7 },
{ "date": "2026-01-17", "commits": 9 },
{ "date": "2026-01-18", "commits": 10 },
{ "date": "2026-01-19", "commits": 0 },
{ "date": "2026-01-20", "commits": 0 },
{ "date": "2026-01-21", "commits": 7 },
{ "date": "2026-01-22", "commits": 7 },
{ "date": "2026-01-23", "commits": 7 },
{ "date": "2026-01-24", "commits": 3 },
{ "date": "2026-01-25", "commits": 3 },
{ "date": "2026-01-26", "commits": 3 },
{ "date": "2026-01-27", "commits": 0 },
{ "date": "2026-01-28", "commits": 0 },
{ "date": "2026-01-29", "commits": 1 },
{ "date": "2026-01-30", "commits": 2 },
{ "date": "2026-01-31", "commits": 3 },
{ "date": "2026-02-01", "commits": 0 },
{ "date": "2026-02-02", "commits": 0 },
{ "date": "2026-02-03", "commits": 0 },
{ "date": "2026-02-04", "commits": 3 },
{ "date": "2026-02-05", "commits": 0 },
{ "date": "2026-02-06", "commits": 1 },
{ "date": "2026-02-07", "commits": 2 },
{ "date": "2026-02-08", "commits": 3 },
{ "date": "2026-02-09", "commits": 0 },
{ "date": "2026-02-10", "commits": 0 },
{ "date": "2026-02-11", "commits": 3 },
{ "date": "2026-02-12", "commits": 4 },
{ "date": "2026-02-13", "commits": 1 },
{ "date": "2026-02-14", "commits": 2 },
{ "date": "2026-02-15", "commits": 2 },
{ "date": "2026-02-16", "commits": 0 },
{ "date": "2026-02-17", "commits": 3 },
{ "date": "2026-02-18", "commits": 1 },
{ "date": "2026-02-19", "commits": 2 },
{ "date": "2026-02-20", "commits": 3 },
{ "date": "2026-02-21", "commits": 0 },
{ "date": "2026-02-22", "commits": 1 },
{ "date": "2026-02-23", "commits": 0 },
{ "date": "2026-02-24", "commits": 0 },
{ "date": "2026-02-25", "commits": 0 },
{ "date": "2026-02-26", "commits": 1 },
{ "date": "2026-02-27", "commits": 2 },
{ "date": "2026-02-28", "commits": 3 },
{ "date": "2026-03-01", "commits": 0 },
{ "date": "2026-03-02", "commits": 0 },
{ "date": "2026-03-03", "commits": 0 },
{ "date": "2026-03-04", "commits": 3 },
{ "date": "2026-03-05", "commits": 0 },
{ "date": "2026-03-06", "commits": 1 },
{ "date": "2026-03-07", "commits": 2 },
{ "date": "2026-03-08", "commits": 3 },
{ "date": "2026-03-09", "commits": 0 },
{ "date": "2026-03-10", "commits": 0 },
{ "date": "2026-03-11", "commits": 5 },
{ "date": "2026-03-12", "commits": 8 },
{ "date": "2026-03-13", "commits": 7 },
{ "date": "2026-03-14", "commits": 10 },
{ "date": "2026-03-15", "commits": 12 },
{ "date": "2026-03-16", "commits": 0 },
{ "date": "2026-03-17", "commits": 0 },
{ "date": "2026-03-18", "commits": 10 },
{ "date": "2026-03-19", "commits": 10 },
{ "date": "2026-03-20", "commits": 9 },
{ "date": "2026-03-21", "commits": 5 },
{ "date": "2026-03-22", "commits": 4 },
{ "date": "2026-03-23", "commits": 0 },
{ "date": "2026-03-24", "commits": 0 },
{ "date": "2026-03-25", "commits": 0 },
{ "date": "2026-03-26", "commits": 1 },
{ "date": "2026-03-27", "commits": 2 },
{ "date": "2026-03-28", "commits": 3 },
{ "date": "2026-03-29", "commits": 0 },
{ "date": "2026-03-30", "commits": 0 },
{ "date": "2026-03-31", "commits": 0 },
{ "date": "2026-04-01", "commits": 3 },
{ "date": "2026-04-02", "commits": 0 },
{ "date": "2026-04-03", "commits": 1 },
{ "date": "2026-04-04", "commits": 2 },
{ "date": "2026-04-05", "commits": 3 },
{ "date": "2026-04-06", "commits": 0 },
{ "date": "2026-04-07", "commits": 0 },
{ "date": "2026-04-08", "commits": 2 },
{ "date": "2026-04-09", "commits": 3 },
{ "date": "2026-04-10", "commits": 0 },
{ "date": "2026-04-11", "commits": 1 },
{ "date": "2026-04-12", "commits": 2 },
{ "date": "2026-04-13", "commits": 3 },
{ "date": "2026-04-14", "commits": 0 },
{ "date": "2026-04-15", "commits": 1 },
{ "date": "2026-04-16", "commits": 2 },
{ "date": "2026-04-17", "commits": 3 },
{ "date": "2026-04-18", "commits": 0 },
{ "date": "2026-04-19", "commits": 1 },
{ "date": "2026-04-20", "commits": 0 },
{ "date": "2026-04-21", "commits": 0 },
{ "date": "2026-04-22", "commits": 0 },
{ "date": "2026-04-23", "commits": 1 },
{ "date": "2026-04-24", "commits": 2 },
{ "date": "2026-04-25", "commits": 3 },
{ "date": "2026-04-26", "commits": 0 },
{ "date": "2026-04-27", "commits": 0 },
{ "date": "2026-04-28", "commits": 0 },
{ "date": "2026-04-29", "commits": 3 },
{ "date": "2026-04-30", "commits": 0 },
{ "date": "2026-05-01", "commits": 1 },
{ "date": "2026-05-02", "commits": 2 },
{ "date": "2026-05-03", "commits": 3 },
{ "date": "2026-05-04", "commits": 0 },
{ "date": "2026-05-05", "commits": 3 },
{ "date": "2026-05-06", "commits": 5 },
{ "date": "2026-05-07", "commits": 8 },
{ "date": "2026-05-08", "commits": 7 },
{ "date": "2026-05-09", "commits": 10 },
{ "date": "2026-05-10", "commits": 12 },
{ "date": "2026-05-11", "commits": 0 },
{ "date": "2026-05-12", "commits": 0 },
{ "date": "2026-05-13", "commits": 13 },
{ "date": "2026-05-14", "commits": 13 },
{ "date": "2026-05-15", "commits": 12 },
{ "date": "2026-05-16", "commits": 7 },
{ "date": "2026-05-17", "commits": 6 },
{ "date": "2026-05-18", "commits": 0 },
{ "date": "2026-05-19", "commits": 0 },
{ "date": "2026-05-20", "commits": 1 },
{ "date": "2026-05-21", "commits": 1 },
{ "date": "2026-05-22", "commits": 2 },
{ "date": "2026-05-23", "commits": 3 },
{ "date": "2026-05-24", "commits": 0 },
{ "date": "2026-05-25", "commits": 0 },
{ "date": "2026-05-26", "commits": 0 },
{ "date": "2026-05-27", "commits": 3 },
{ "date": "2026-05-28", "commits": 0 },
{ "date": "2026-05-29", "commits": 1 },
{ "date": "2026-05-30", "commits": 2 },
{ "date": "2026-05-31", "commits": 3 },
{ "date": "2026-06-01", "commits": 0 },
{ "date": "2026-06-02", "commits": 0 },
{ "date": "2026-06-03", "commits": 2 },
{ "date": "2026-06-04", "commits": 3 },
{ "date": "2026-06-05", "commits": 0 },
{ "date": "2026-06-06", "commits": 1 },
{ "date": "2026-06-07", "commits": 2 },
{ "date": "2026-06-08", "commits": 0 },
{ "date": "2026-06-09", "commits": 0 },
{ "date": "2026-06-10", "commits": 1 },
{ "date": "2026-06-11", "commits": 2 },
{ "date": "2026-06-12", "commits": 3 },
{ "date": "2026-06-13", "commits": 0 },
{ "date": "2026-06-14", "commits": 1 },
{ "date": "2026-06-15", "commits": 0 },
{ "date": "2026-06-16", "commits": 0 },
{ "date": "2026-06-17", "commits": 0 },
{ "date": "2026-06-18", "commits": 1 },
{ "date": "2026-06-19", "commits": 2 },
{ "date": "2026-06-20", "commits": 3 },
{ "date": "2026-06-21", "commits": 0 },
{ "date": "2026-06-22", "commits": 0 },
{ "date": "2026-06-23", "commits": 0 },
{ "date": "2026-06-24", "commits": 3 },
{ "date": "2026-06-25", "commits": 0 },
{ "date": "2026-06-26", "commits": 1 },
{ "date": "2026-06-27", "commits": 2 },
{ "date": "2026-06-28", "commits": 3 },
{ "date": "2026-06-29", "commits": 3 },
{ "date": "2026-06-30", "commits": 0 },
{ "date": "2026-07-01", "commits": 4 },
{ "date": "2026-07-02", "commits": 6 },
{ "date": "2026-07-03", "commits": 6 },
{ "date": "2026-07-04", "commits": 9 },
{ "date": "2026-07-05", "commits": 12 },
{ "date": "2026-07-06", "commits": 0 },
{ "date": "2026-07-07", "commits": 0 },
{ "date": "2026-07-08", "commits": 14 },
{ "date": "2026-07-09", "commits": 15 },
{ "date": "2026-07-10", "commits": 15 },
{ "date": "2026-07-11", "commits": 10 },
{ "date": "2026-07-12", "commits": 9 },
{ "date": "2026-07-13", "commits": 0 },
{ "date": "2026-07-14", "commits": 0 },
{ "date": "2026-07-15", "commits": 2 },
{ "date": "2026-07-16", "commits": 2 },
{ "date": "2026-07-17", "commits": 2 },
{ "date": "2026-07-18", "commits": 3 },
{ "date": "2026-07-19", "commits": 0 },
{ "date": "2026-07-20", "commits": 0 },
{ "date": "2026-07-21", "commits": 3 },
{ "date": "2026-07-22", "commits": 3 },
{ "date": "2026-07-23", "commits": 0 },
{ "date": "2026-07-24", "commits": 1 },
{ "date": "2026-07-25", "commits": 2 },
{ "date": "2026-07-26", "commits": 3 },
{ "date": "2026-07-27", "commits": 0 },
{ "date": "2026-07-28", "commits": 0 },
{ "date": "2026-07-29", "commits": 2 },
{ "date": "2026-07-30", "commits": 3 },
{ "date": "2026-07-31", "commits": 0 },
{ "date": "2026-08-01", "commits": 1 },
{ "date": "2026-08-02", "commits": 2 },
{ "date": "2026-08-03", "commits": 0 },
{ "date": "2026-08-04", "commits": 0 },
{ "date": "2026-08-05", "commits": 1 },
{ "date": "2026-08-06", "commits": 2 },
{ "date": "2026-08-07", "commits": 3 },
{ "date": "2026-08-08", "commits": 0 },
{ "date": "2026-08-09", "commits": 1 },
{ "date": "2026-08-10", "commits": 0 },
{ "date": "2026-08-11", "commits": 0 },
{ "date": "2026-08-12", "commits": 0 },
{ "date": "2026-08-13", "commits": 1 },
{ "date": "2026-08-14", "commits": 2 },
{ "date": "2026-08-15", "commits": 3 },
{ "date": "2026-08-16", "commits": 0 },
{ "date": "2026-08-17", "commits": 0 },
{ "date": "2026-08-18", "commits": 0 },
{ "date": "2026-08-19", "commits": 3 },
{ "date": "2026-08-20", "commits": 0 },
{ "date": "2026-08-21", "commits": 1 },
{ "date": "2026-08-22", "commits": 2 },
{ "date": "2026-08-23", "commits": 3 },
{ "date": "2026-08-24", "commits": 0 },
{ "date": "2026-08-25", "commits": 0 },
{ "date": "2026-08-26", "commits": 3 },
{ "date": "2026-08-27", "commits": 5 },
{ "date": "2026-08-28", "commits": 4 },
{ "date": "2026-08-29", "commits": 7 },
{ "date": "2026-08-30", "commits": 11 },
{ "date": "2026-08-31", "commits": 0 },
{ "date": "2026-09-01", "commits": 0 },
{ "date": "2026-09-02", "commits": 15 },
{ "date": "2026-09-03", "commits": 16 },
{ "date": "2026-09-04", "commits": 16 },
{ "date": "2026-09-05", "commits": 12 },
{ "date": "2026-09-06", "commits": 11 },
{ "date": "2026-09-07", "commits": 0 },
{ "date": "2026-09-08", "commits": 0 },
{ "date": "2026-09-09", "commits": 3 },
{ "date": "2026-09-10", "commits": 3 },
{ "date": "2026-09-11", "commits": 2 },
{ "date": "2026-09-12", "commits": 3 },
{ "date": "2026-09-13", "commits": 0 },
{ "date": "2026-09-14", "commits": 3 },
{ "date": "2026-09-15", "commits": 0 },
{ "date": "2026-09-16", "commits": 3 },
{ "date": "2026-09-17", "commits": 0 },
{ "date": "2026-09-18", "commits": 1 },
{ "date": "2026-09-19", "commits": 2 },
{ "date": "2026-09-20", "commits": 3 },
{ "date": "2026-09-21", "commits": 0 },
{ "date": "2026-09-22", "commits": 0 },
{ "date": "2026-09-23", "commits": 2 },
{ "date": "2026-09-24", "commits": 3 },
{ "date": "2026-09-25", "commits": 0 },
{ "date": "2026-09-26", "commits": 1 },
{ "date": "2026-09-27", "commits": 2 },
{ "date": "2026-09-28", "commits": 0 },
{ "date": "2026-09-29", "commits": 0 },
{ "date": "2026-09-30", "commits": 1 },
{ "date": "2026-10-01", "commits": 2 },
{ "date": "2026-10-02", "commits": 3 },
{ "date": "2026-10-03", "commits": 0 },
{ "date": "2026-10-04", "commits": 1 },
{ "date": "2026-10-05", "commits": 0 },
{ "date": "2026-10-06", "commits": 3 },
{ "date": "2026-10-07", "commits": 0 },
];
export function Example() {
return (
);
}
```
#### A quarter with gaps
Ninety days with missing readings and a few days still to come: gaps stay on the floor, future days are outlines.
```tsx
'use client';
import { SkylineCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const calendarActivity = [
{ "date": "2026-07-01", "visits": null },
{ "date": "2026-07-02", "visits": 337 },
{ "date": "2026-07-03", "visits": 474 },
{ "date": "2026-07-04", "visits": 611 },
{ "date": "2026-07-05", "visits": 748 },
{ "date": "2026-07-06", "visits": 885 },
{ "date": "2026-07-07", "visits": 1022 },
{ "date": "2026-07-08", "visits": 209 },
{ "date": "2026-07-09", "visits": 346 },
{ "date": "2026-07-10", "visits": 483 },
{ "date": "2026-07-11", "visits": 620 },
{ "date": "2026-07-12", "visits": 757 },
{ "date": "2026-07-13", "visits": 894 },
{ "date": "2026-07-14", "visits": 0 },
{ "date": "2026-07-15", "visits": 218 },
{ "date": "2026-07-16", "visits": 355 },
{ "date": "2026-07-17", "visits": 492 },
{ "date": "2026-07-18", "visits": 629 },
{ "date": "2026-07-19", "visits": 766 },
{ "date": "2026-07-20", "visits": null },
{ "date": "2026-07-21", "visits": 1040 },
{ "date": "2026-07-22", "visits": 227 },
{ "date": "2026-07-23", "visits": 364 },
{ "date": "2026-07-24", "visits": 501 },
{ "date": "2026-07-25", "visits": 638 },
{ "date": "2026-07-26", "visits": 775 },
{ "date": "2026-07-27", "visits": 0 },
{ "date": "2026-07-28", "visits": 1049 },
{ "date": "2026-07-29", "visits": 236 },
{ "date": "2026-07-30", "visits": 373 },
{ "date": "2026-07-31", "visits": 510 },
{ "date": "2026-08-01", "visits": 647 },
{ "date": "2026-08-02", "visits": 784 },
{ "date": "2026-08-03", "visits": 921 },
{ "date": "2026-08-04", "visits": 1058 },
{ "date": "2026-08-05", "visits": 245 },
{ "date": "2026-08-06", "visits": 382 },
{ "date": "2026-08-07", "visits": 519 },
{ "date": "2026-08-08", "visits": null },
{ "date": "2026-08-09", "visits": 0 },
{ "date": "2026-08-10", "visits": 930 },
{ "date": "2026-08-11", "visits": 1067 },
{ "date": "2026-08-12", "visits": 254 },
{ "date": "2026-08-13", "visits": 391 },
{ "date": "2026-08-14", "visits": 528 },
{ "date": "2026-08-15", "visits": 665 },
{ "date": "2026-08-16", "visits": 802 },
{ "date": "2026-08-17", "visits": 939 },
{ "date": "2026-08-18", "visits": 1076 },
{ "date": "2026-08-19", "visits": 263 },
{ "date": "2026-08-20", "visits": 400 },
{ "date": "2026-08-21", "visits": 537 },
{ "date": "2026-08-22", "visits": 0 },
{ "date": "2026-08-23", "visits": 811 },
{ "date": "2026-08-24", "visits": 948 },
{ "date": "2026-08-25", "visits": 1085 },
{ "date": "2026-08-26", "visits": 272 },
{ "date": "2026-08-27", "visits": null },
{ "date": "2026-08-28", "visits": 546 },
{ "date": "2026-08-29", "visits": 683 },
{ "date": "2026-08-30", "visits": 820 },
{ "date": "2026-08-31", "visits": 957 },
{ "date": "2026-09-01", "visits": 1094 },
{ "date": "2026-09-02", "visits": 281 },
{ "date": "2026-09-03", "visits": 418 },
{ "date": "2026-09-04", "visits": 0 },
{ "date": "2026-09-05", "visits": 692 },
{ "date": "2026-09-06", "visits": 829 },
{ "date": "2026-09-07", "visits": 966 },
{ "date": "2026-09-08", "visits": 1103 },
{ "date": "2026-09-09", "visits": 290 },
{ "date": "2026-09-10", "visits": 427 },
{ "date": "2026-09-11", "visits": 564 },
{ "date": "2026-09-12", "visits": 701 },
{ "date": "2026-09-13", "visits": 838 },
{ "date": "2026-09-14", "visits": 975 },
{ "date": "2026-09-15", "visits": null },
{ "date": "2026-09-16", "visits": 299 },
{ "date": "2026-09-17", "visits": 0 },
{ "date": "2026-09-18", "visits": 573 },
{ "date": "2026-09-19", "visits": 710 },
{ "date": "2026-09-20", "visits": 847 },
{ "date": "2026-09-21", "visits": 984 },
{ "date": "2026-09-22", "visits": 1121 },
{ "date": "2026-09-23", "visits": 308 },
{ "date": "2026-09-24", "visits": 445 },
{ "date": "2026-09-25", "visits": 582 },
{ "date": "2026-09-26", "visits": 719 },
{ "date": "2026-09-27", "visits": 856 },
{ "date": "2026-09-28", "visits": 993 },
{ "date": "2026-09-29", "visits": 1130 },
{ "date": "2026-09-30", "visits": 0 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const yearContributions = [
{ date: '2025-10-08', commits: 4 },
{ date: '2025-10-09', commits: 11 },
// …one row per day
];
```
One row per UTC day. Bounds default to the observed dates and span at most ten years. Height and color both carry the value. Null days stay a low grey slab, measured zero keeps a tinted slab, and days after today lie flat as outlines. Duplicate days are rejected; aggregate them first.
### Hover
Hover or focus a prism to read its value in the headline; hit testing follows the prism, not the box around it, and nearer prisms win where they overlap. Click or press Enter to pin; Escape releases. Arrow keys step through cells. Prisms rise from the floor on load, back rows first; reduced motion skips it.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 320px. Dense data may expand within the scrollable viewport.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `date` (`date, string, or numeric key of Row`): UTC date per day; numbers are milliseconds since the Unix epoch.
- `value` (`numeric key of Row`): Height, color, and headline.
- `from` (`string | number | Date`): Inclusive UTC bounds. Defaults to the first and last observed dates.
- `to` (`string | number | Date`): Inclusive UTC bounds. Defaults to the first and last observed dates.
- `today` (`string | number | Date`): UTC cutoff for future days; defaults to today.
- `weekStartsOn` (`0 | 1`): Sunday (0) or Monday (1, default).
- `domain` (`[number, number]`): Fixed value domain that must contain every value. Defaults to zero through the largest.
- `rise` (`number`): How many cell lengths the largest value rises above the floor, default 5.
- `gap` (`number`): Space between neighbouring prisms as a share of a cell, 0 to 0.6, default 0.2.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Block city: `BlockCityCard`
Two categories as a city block: one prism per pair, so the tallest corner of the business stands out. Docs: https://liltui.vercel.app/charts/block-city
```tsx
import { BlockCityCard } from '@lilt-ui/charts';
```
### Complete examples
#### Sales by region
```tsx
'use client';
import { BlockCityCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const regionSales = [
{ "region": "North", "month": "Jan", "sales": 20 },
{ "region": "North", "month": "Feb", "sales": 66 },
{ "region": "North", "month": "Mar", "sales": 34 },
{ "region": "North", "month": "Apr", "sales": 80 },
{ "region": "North", "month": "May", "sales": 48 },
{ "region": "North", "month": "Jun", "sales": 94 },
{ "region": "North", "month": "Jul", "sales": 62 },
{ "region": "North", "month": "Aug", "sales": 108 },
{ "region": "East", "month": "Jan", "sales": 86 },
{ "region": "East", "month": "Feb", "sales": 54 },
{ "region": "East", "month": "Mar", "sales": 100 },
{ "region": "East", "month": "Apr", "sales": 68 },
{ "region": "East", "month": "May", "sales": 36 },
{ "region": "East", "month": "Jun", "sales": 82 },
{ "region": "East", "month": "Jul", "sales": 50 },
{ "region": "East", "month": "Aug", "sales": 96 },
{ "region": "South", "month": "Jan", "sales": 74 },
{ "region": "South", "month": "Feb", "sales": 42 },
{ "region": "South", "month": "Mar", "sales": 88 },
{ "region": "South", "month": "Apr", "sales": 56 },
{ "region": "South", "month": "May", "sales": 102 },
{ "region": "South", "month": "Jun", "sales": 70 },
{ "region": "South", "month": "Jul", "sales": 116 },
{ "region": "South", "month": "Aug", "sales": 84 },
{ "region": "West", "month": "Jan", "sales": 62 },
{ "region": "West", "month": "Feb", "sales": 30 },
{ "region": "West", "month": "Mar", "sales": 76 },
{ "region": "West", "month": "Apr", "sales": 44 },
{ "region": "West", "month": "May", "sales": 90 },
{ "region": "West", "month": "Jun", "sales": 58 },
{ "region": "West", "month": "Jul", "sales": 104 },
{ "region": "West", "month": "Aug", "sales": 72 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const regionSales = [
{ region: 'North', month: 'Jan', sales: 62 },
{ region: 'North', month: 'Feb', sales: 98 },
// …one row per region and month
];
```
One row per x and y pair. Columns and rows keep the order they first appear in. A pair with no row stays a low grey slab, so a gap never reads as zero. Duplicate pairs are rejected; sum them first.
### Hover
Hover or focus a prism to read its value in the headline; hit testing follows the prism, not the box around it, and nearer prisms win where they overlap. Click or press Enter to pin; Escape releases. Arrow keys step through cells. Prisms rise from the floor on load, back rows first; reduced motion skips it.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 300px. Dense data may expand within the scrollable viewport.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `x` (`text key of Row`): Columns, running away to the right.
- `y` (`text key of Row`): Rows, coming toward the viewer.
- `value` (`numeric key of Row`): Height, color, and headline.
- `domain` (`[number, number]`): Fixed value domain that must contain every value. Defaults to zero through the largest.
- `rise` (`number`): How many cell lengths the largest value rises above the floor, default 4.
- `gap` (`number`): Space between neighbouring prisms as a share of a cell, 0 to 0.6, default 0.2.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Ridgeline: `RidgelineCard`
Layered ridges receding into depth, so the shape of every row reads at a glance. Docs: https://liltui.vercel.app/charts/ridgeline
```tsx
import { RidgelineCard } from '@lilt-ui/charts';
```
### Complete examples
#### Traffic by hour
```tsx
'use client';
import { RidgelineCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const weekdayTraffic = [
{ "day": "Mon", "hour": "00:00", "visits": 40 },
{ "day": "Mon", "hour": "01:00", "visits": 64 },
{ "day": "Mon", "hour": "02:00", "visits": 88 },
{ "day": "Mon", "hour": "03:00", "visits": 58 },
{ "day": "Mon", "hour": "04:00", "visits": 84 },
{ "day": "Mon", "hour": "05:00", "visits": 59 },
{ "day": "Mon", "hour": "06:00", "visits": 105 },
{ "day": "Mon", "hour": "07:00", "visits": 176 },
{ "day": "Mon", "hour": "08:00", "visits": 449 },
{ "day": "Mon", "hour": "09:00", "visits": 649 },
{ "day": "Mon", "hour": "10:00", "visits": 679 },
{ "day": "Mon", "hour": "11:00", "visits": 689 },
{ "day": "Mon", "hour": "12:00", "visits": 771 },
{ "day": "Mon", "hour": "13:00", "visits": 928 },
{ "day": "Mon", "hour": "14:00", "visits": 952 },
{ "day": "Mon", "hour": "15:00", "visits": 921 },
{ "day": "Mon", "hour": "16:00", "visits": 747 },
{ "day": "Mon", "hour": "17:00", "visits": 583 },
{ "day": "Mon", "hour": "18:00", "visits": 371 },
{ "day": "Mon", "hour": "19:00", "visits": 253 },
{ "day": "Mon", "hour": "20:00", "visits": 183 },
{ "day": "Mon", "hour": "21:00", "visits": 100 },
{ "day": "Mon", "hour": "22:00", "visits": 98 },
{ "day": "Mon", "hour": "23:00", "visits": 58 },
{ "day": "Tue", "hour": "00:00", "visits": 82 },
{ "day": "Tue", "hour": "01:00", "visits": 52 },
{ "day": "Tue", "hour": "02:00", "visits": 76 },
{ "day": "Tue", "hour": "03:00", "visits": 46 },
{ "day": "Tue", "hour": "04:00", "visits": 72 },
{ "day": "Tue", "hour": "05:00", "visits": 47 },
{ "day": "Tue", "hour": "06:00", "visits": 93 },
{ "day": "Tue", "hour": "07:00", "visits": 218 },
{ "day": "Tue", "hour": "08:00", "visits": 437 },
{ "day": "Tue", "hour": "09:00", "visits": 691 },
{ "day": "Tue", "hour": "10:00", "visits": 667 },
{ "day": "Tue", "hour": "11:00", "visits": 677 },
{ "day": "Tue", "hour": "12:00", "visits": 759 },
{ "day": "Tue", "hour": "13:00", "visits": 916 },
{ "day": "Tue", "hour": "14:00", "visits": 940 },
{ "day": "Tue", "hour": "15:00", "visits": 909 },
{ "day": "Tue", "hour": "16:00", "visits": 789 },
{ "day": "Tue", "hour": "17:00", "visits": 571 },
{ "day": "Tue", "hour": "18:00", "visits": 413 },
{ "day": "Tue", "hour": "19:00", "visits": 241 },
{ "day": "Tue", "hour": "20:00", "visits": 171 },
{ "day": "Tue", "hour": "21:00", "visits": 88 },
{ "day": "Tue", "hour": "22:00", "visits": 86 },
{ "day": "Tue", "hour": "23:00", "visits": 46 },
{ "day": "Wed", "hour": "00:00", "visits": 70 },
{ "day": "Wed", "hour": "01:00", "visits": 40 },
{ "day": "Wed", "hour": "02:00", "visits": 64 },
{ "day": "Wed", "hour": "03:00", "visits": 88 },
{ "day": "Wed", "hour": "04:00", "visits": 60 },
{ "day": "Wed", "hour": "05:00", "visits": 89 },
{ "day": "Wed", "hour": "06:00", "visits": 81 },
{ "day": "Wed", "hour": "07:00", "visits": 206 },
{ "day": "Wed", "hour": "08:00", "visits": 425 },
{ "day": "Wed", "hour": "09:00", "visits": 679 },
{ "day": "Wed", "hour": "10:00", "visits": 655 },
{ "day": "Wed", "hour": "11:00", "visits": 665 },
{ "day": "Wed", "hour": "12:00", "visits": 801 },
{ "day": "Wed", "hour": "13:00", "visits": 904 },
{ "day": "Wed", "hour": "14:00", "visits": 982 },
{ "day": "Wed", "hour": "15:00", "visits": 897 },
{ "day": "Wed", "hour": "16:00", "visits": 777 },
{ "day": "Wed", "hour": "17:00", "visits": 559 },
{ "day": "Wed", "hour": "18:00", "visits": 401 },
{ "day": "Wed", "hour": "19:00", "visits": 229 },
{ "day": "Wed", "hour": "20:00", "visits": 159 },
{ "day": "Wed", "hour": "21:00", "visits": 130 },
{ "day": "Wed", "hour": "22:00", "visits": 74 },
{ "day": "Wed", "hour": "23:00", "visits": 88 },
{ "day": "Thu", "hour": "00:00", "visits": 58 },
{ "day": "Thu", "hour": "01:00", "visits": 82 },
{ "day": "Thu", "hour": "02:00", "visits": 52 },
{ "day": "Thu", "hour": "03:00", "visits": 76 },
{ "day": "Thu", "hour": "04:00", "visits": 48 },
{ "day": "Thu", "hour": "05:00", "visits": 77 },
{ "day": "Thu", "hour": "06:00", "visits": 69 },
{ "day": "Thu", "hour": "07:00", "visits": 194 },
{ "day": "Thu", "hour": "08:00", "visits": 467 },
{ "day": "Thu", "hour": "09:00", "visits": 667 },
{ "day": "Thu", "hour": "10:00", "visits": 697 },
{ "day": "Thu", "hour": "11:00", "visits": 653 },
{ "day": "Thu", "hour": "12:00", "visits": 789 },
{ "day": "Thu", "hour": "13:00", "visits": 892 },
{ "day": "Thu", "hour": "14:00", "visits": 970 },
{ "day": "Thu", "hour": "15:00", "visits": 885 },
{ "day": "Thu", "hour": "16:00", "visits": 765 },
{ "day": "Thu", "hour": "17:00", "visits": 601 },
{ "day": "Thu", "hour": "18:00", "visits": 389 },
{ "day": "Thu", "hour": "19:00", "visits": 271 },
{ "day": "Thu", "hour": "20:00", "visits": 147 },
{ "day": "Thu", "hour": "21:00", "visits": 118 },
{ "day": "Thu", "hour": "22:00", "visits": 62 },
{ "day": "Thu", "hour": "23:00", "visits": 76 },
{ "day": "Fri", "hour": "00:00", "visits": 46 },
{ "day": "Fri", "hour": "01:00", "visits": 70 },
{ "day": "Fri", "hour": "02:00", "visits": 40 },
{ "day": "Fri", "hour": "03:00", "visits": 64 },
{ "day": "Fri", "hour": "04:00", "visits": 90 },
{ "day": "Fri", "hour": "05:00", "visits": 65 },
{ "day": "Fri", "hour": "06:00", "visits": 111 },
{ "day": "Fri", "hour": "07:00", "visits": 182 },
{ "day": "Fri", "hour": "08:00", "visits": 455 },
{ "day": "Fri", "hour": "09:00", "visits": 655 },
{ "day": "Fri", "hour": "10:00", "visits": 685 },
{ "day": "Fri", "hour": "11:00", "visits": 641 },
{ "day": "Fri", "hour": "12:00", "visits": 777 },
{ "day": "Fri", "hour": "13:00", "visits": 934 },
{ "day": "Fri", "hour": "14:00", "visits": 958 },
{ "day": "Fri", "hour": "15:00", "visits": 927 },
{ "day": "Fri", "hour": "16:00", "visits": 753 },
{ "day": "Fri", "hour": "17:00", "visits": 589 },
{ "day": "Fri", "hour": "18:00", "visits": 377 },
{ "day": "Fri", "hour": "19:00", "visits": 259 },
{ "day": "Fri", "hour": "20:00", "visits": 135 },
{ "day": "Fri", "hour": "21:00", "visits": 106 },
{ "day": "Fri", "hour": "22:00", "visits": 104 },
{ "day": "Fri", "hour": "23:00", "visits": 64 },
{ "day": "Sat", "hour": "00:00", "visits": 88 },
{ "day": "Sat", "hour": "01:00", "visits": 58 },
{ "day": "Sat", "hour": "02:00", "visits": 82 },
{ "day": "Sat", "hour": "03:00", "visits": 52 },
{ "day": "Sat", "hour": "04:00", "visits": 76 },
{ "day": "Sat", "hour": "05:00", "visits": 46 },
{ "day": "Sat", "hour": "06:00", "visits": 71 },
{ "day": "Sat", "hour": "07:00", "visits": 43 },
{ "day": "Sat", "hour": "08:00", "visits": 74 },
{ "day": "Sat", "hour": "09:00", "visits": 112 },
{ "day": "Sat", "hour": "10:00", "visits": 113 },
{ "day": "Sat", "hour": "11:00", "visits": 191 },
{ "day": "Sat", "hour": "12:00", "visits": 243 },
{ "day": "Sat", "hour": "13:00", "visits": 372 },
{ "day": "Sat", "hour": "14:00", "visits": 451 },
{ "day": "Sat", "hour": "15:00", "visits": 558 },
{ "day": "Sat", "hour": "16:00", "visits": 560 },
{ "day": "Sat", "hour": "17:00", "visits": 552 },
{ "day": "Sat", "hour": "18:00", "visits": 493 },
{ "day": "Sat", "hour": "19:00", "visits": 354 },
{ "day": "Sat", "hour": "20:00", "visits": 273 },
{ "day": "Sat", "hour": "21:00", "visits": 161 },
{ "day": "Sat", "hour": "22:00", "visits": 131 },
{ "day": "Sat", "hour": "23:00", "visits": 70 },
{ "day": "Sun", "hour": "00:00", "visits": 76 },
{ "day": "Sun", "hour": "01:00", "visits": 46 },
{ "day": "Sun", "hour": "02:00", "visits": 70 },
{ "day": "Sun", "hour": "03:00", "visits": 40 },
{ "day": "Sun", "hour": "04:00", "visits": 64 },
{ "day": "Sun", "hour": "05:00", "visits": 88 },
{ "day": "Sun", "hour": "06:00", "visits": 59 },
{ "day": "Sun", "hour": "07:00", "visits": 85 },
{ "day": "Sun", "hour": "08:00", "visits": 62 },
{ "day": "Sun", "hour": "09:00", "visits": 100 },
{ "day": "Sun", "hour": "10:00", "visits": 101 },
{ "day": "Sun", "hour": "11:00", "visits": 179 },
{ "day": "Sun", "hour": "12:00", "visits": 231 },
{ "day": "Sun", "hour": "13:00", "visits": 360 },
{ "day": "Sun", "hour": "14:00", "visits": 493 },
{ "day": "Sun", "hour": "15:00", "visits": 546 },
{ "day": "Sun", "hour": "16:00", "visits": 602 },
{ "day": "Sun", "hour": "17:00", "visits": 540 },
{ "day": "Sun", "hour": "18:00", "visits": 481 },
{ "day": "Sun", "hour": "19:00", "visits": 342 },
{ "day": "Sun", "hour": "20:00", "visits": 261 },
{ "day": "Sun", "hour": "21:00", "visits": 149 },
{ "day": "Sun", "hour": "22:00", "visits": 119 },
{ "day": "Sun", "hour": "23:00", "visits": 112 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const weekdayTraffic = [
{ day: 'Mon', hour: '00:00', visits: 64 },
{ day: 'Mon', hour: '01:00', visits: 58 },
// …one row per day and hour
];
```
One row per series and x position. Ridges stack back to front in the order series first appear, and x positions keep their first-seen order. Every ridge shares one value scale so heights compare. Null draws on the baseline but reads as no data; duplicate pairs are rejected.
### Hover
Hover or focus anywhere under a ridge to read that point in the headline, with a dot on the line and a rule to its baseline; the other ridges soften. Nearer ridges win where they overlap. Click or press Enter to pin; Escape releases. Arrow keys walk along a ridge and on to the next.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 300px. Dense data may expand within the scrollable viewport.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `series` (`text key of Row`): One ridge per value, back to front.
- `x` (`text, number, or date key of Row`): Position along each ridge, in first-seen order.
- `value` (`numeric key of Row`): Ridge height and headline.
- `overlap` (`number`): How many rows the tallest peak rises over the ridges behind it, default 2.2.
- `domain` (`[number, number]`): Fixed value domain that must contain every value. Defaults to zero through the largest.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Spiral year: `SpiralYearCard`
Time as a coil, one turn per year, so the same season lines up across every year. Docs: https://liltui.vercel.app/charts/spiral-year
```tsx
import { SpiralYearCard } from '@lilt-ui/charts';
```
### Complete examples
#### Daily steps
```tsx
'use client';
import { SpiralYearCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const dailySteps = [
{ "date": "2024-01-01", "steps": 4000 },
{ "date": "2024-01-02", "steps": 4719 },
{ "date": "2024-01-03", "steps": 5439 },
{ "date": "2024-01-04", "steps": 6160 },
{ "date": "2024-01-05", "steps": 4482 },
{ "date": "2024-01-06", "steps": 8204 },
{ "date": "2024-01-07", "steps": 5927 },
{ "date": "2024-01-08", "steps": 4251 },
{ "date": "2024-01-09", "steps": 4976 },
{ "date": "2024-01-10", "steps": 5701 },
{ "date": "2024-01-11", "steps": 6427 },
{ "date": "2024-01-12", "steps": 4754 },
{ "date": "2024-01-13", "steps": 8481 },
{ "date": "2024-01-14", "steps": 6209 },
{ "date": "2024-01-15", "steps": 4538 },
{ "date": "2024-01-16", "steps": 5268 },
{ "date": "2024-01-17", "steps": 5998 },
{ "date": "2024-01-18", "steps": 4329 },
{ "date": "2024-01-19", "steps": 5061 },
{ "date": "2024-01-20", "steps": 8793 },
{ "date": "2024-01-21", "steps": 6527 },
{ "date": "2024-01-22", "steps": 4860 },
{ "date": "2024-01-23", "steps": 5595 },
{ "date": "2024-01-24", "steps": 6330 },
{ "date": "2024-01-25", "steps": 4666 },
{ "date": "2024-01-26", "steps": 5403 },
{ "date": "2024-01-27", "steps": 9140 },
{ "date": "2024-01-28", "steps": 4478 },
{ "date": "2024-01-29", "steps": 5216 },
{ "date": "2024-01-30", "steps": 5956 },
{ "date": "2024-01-31", "steps": 6696 },
{ "date": "2024-02-01", "steps": 5036 },
{ "date": "2024-02-02", "steps": 5777 },
{ "date": "2024-02-03", "steps": 9519 },
{ "date": "2024-02-04", "steps": 4862 },
{ "date": "2024-02-05", "steps": 5605 },
{ "date": "2024-02-06", "steps": 6348 },
{ "date": "2024-02-07", "steps": 4693 },
{ "date": "2024-02-08", "steps": 5437 },
{ "date": "2024-02-09", "steps": 6183 },
{ "date": "2024-02-10", "steps": 9929 },
{ "date": "2024-02-11", "steps": 5275 },
{ "date": "2024-02-12", "steps": 6023 },
{ "date": "2024-02-13", "steps": 6770 },
{ "date": "2024-02-14", "steps": 5119 },
{ "date": "2024-02-15", "steps": 5867 },
{ "date": "2024-02-16", "steps": 6617 },
{ "date": "2024-02-17", "steps": 7967 },
{ "date": "2024-02-18", "steps": 5717 },
{ "date": "2024-02-19", "steps": 6468 },
{ "date": "2024-02-20", "steps": 7219 },
{ "date": "2024-02-21", "steps": 5571 },
{ "date": "2024-02-22", "steps": 6323 },
{ "date": "2024-02-23", "steps": 7076 },
{ "date": "2024-02-24", "steps": 8429 },
{ "date": "2024-02-25", "steps": 6183 },
{ "date": "2024-02-26", "steps": 6937 },
{ "date": "2024-02-27", "steps": 5292 },
{ "date": "2024-02-28", "steps": 6046 },
{ "date": "2024-02-29", "steps": 6802 },
{ "date": "2024-03-01", "steps": 7558 },
{ "date": "2024-03-02", "steps": 8914 },
{ "date": "2024-03-03", "steps": 6670 },
{ "date": "2024-03-04", "steps": 7427 },
{ "date": "2024-03-05", "steps": 5784 },
{ "date": "2024-03-06", "steps": 6542 },
{ "date": "2024-03-07", "steps": 7299 },
{ "date": "2024-03-08", "steps": 5658 },
{ "date": "2024-03-09", "steps": 9416 },
{ "date": "2024-03-10", "steps": 7175 },
{ "date": "2024-03-11", "steps": 7934 },
{ "date": "2024-03-12", "steps": 6293 },
{ "date": "2024-03-13", "steps": 7053 },
{ "date": "2024-03-14", "steps": 7812 },
{ "date": "2024-03-15", "steps": 6172 },
{ "date": "2024-03-16", "steps": 9933 },
{ "date": "2024-03-17", "steps": 7693 },
{ "date": "2024-03-18", "steps": 6054 },
{ "date": "2024-03-19", "steps": 6814 },
{ "date": "2024-03-20", "steps": 7575 },
{ "date": "2024-03-21", "steps": 8337 },
{ "date": "2024-03-22", "steps": 6698 },
{ "date": "2024-03-23", "steps": 10459 },
{ "date": "2024-03-24", "steps": 8221 },
{ "date": "2024-03-25", "steps": 6582 },
{ "date": "2024-03-26", "steps": 7344 },
{ "date": "2024-03-27", "steps": 8106 },
{ "date": "2024-03-28", "steps": 6468 },
{ "date": "2024-03-29", "steps": 7230 },
{ "date": "2024-03-30", "steps": 10992 },
{ "date": "2024-03-31", "steps": 8754 },
{ "date": "2024-04-01", "steps": 7116 },
{ "date": "2024-04-02", "steps": 7878 },
{ "date": "2024-04-03", "steps": 8640 },
{ "date": "2024-04-04", "steps": 7002 },
{ "date": "2024-04-05", "steps": 7763 },
{ "date": "2024-04-06", "steps": 11525 },
{ "date": "2024-04-07", "steps": 6887 },
{ "date": "2024-04-08", "steps": 7649 },
{ "date": "2024-04-09", "steps": 8411 },
{ "date": "2024-04-10", "steps": 9172 },
{ "date": "2024-04-11", "steps": 7534 },
{ "date": "2024-04-12", "steps": 8295 },
{ "date": "2024-04-13", "steps": 12056 },
{ "date": "2024-04-14", "steps": 7417 },
{ "date": "2024-04-15", "steps": 8178 },
{ "date": "2024-04-16", "steps": 8939 },
{ "date": "2024-04-17", "steps": 7299 },
{ "date": "2024-04-18", "steps": 8060 },
{ "date": "2024-04-19", "steps": 8820 },
{ "date": "2024-04-20", "steps": 12580 },
{ "date": "2024-04-21", "steps": 7940 },
{ "date": "2024-04-22", "steps": 8699 },
{ "date": "2024-04-23", "steps": 9458 },
{ "date": "2024-04-24", "steps": 7817 },
{ "date": "2024-04-25", "steps": 8576 },
{ "date": "2024-04-26", "steps": 9334 },
{ "date": "2024-04-27", "steps": 10692 },
{ "date": "2024-04-28", "steps": 8450 },
{ "date": "2024-04-29", "steps": 9207 },
{ "date": "2024-04-30", "steps": 9964 },
{ "date": "2024-05-01", "steps": 8321 },
{ "date": "2024-05-02", "steps": 9077 },
{ "date": "2024-05-03", "steps": 9833 },
{ "date": "2024-05-04", "steps": 11189 },
{ "date": "2024-05-05", "steps": 8944 },
{ "date": "2024-05-06", "steps": 9699 },
{ "date": "2024-05-07", "steps": 8053 },
{ "date": "2024-05-08", "steps": 8807 },
{ "date": "2024-05-09", "steps": 9561 },
{ "date": "2024-05-10", "steps": 10314 },
{ "date": "2024-05-11", "steps": 11666 },
{ "date": "2024-05-12", "steps": 9418 },
{ "date": "2024-05-13", "steps": 10170 },
{ "date": "2024-05-14", "steps": 8521 },
{ "date": "2024-05-15", "steps": 9272 },
{ "date": "2024-05-16", "steps": 10022 },
{ "date": "2024-05-17", "steps": 8372 },
{ "date": "2024-05-18", "steps": 12121 },
{ "date": "2024-05-19", "steps": 9869 },
{ "date": "2024-05-20", "steps": 10618 },
{ "date": "2024-05-21", "steps": 8965 },
{ "date": "2024-05-22", "steps": 9712 },
{ "date": "2024-05-23", "steps": 10458 },
{ "date": "2024-05-24", "steps": 8804 },
{ "date": "2024-05-25", "steps": 12549 },
{ "date": "2024-05-26", "steps": 10294 },
{ "date": "2024-05-27", "steps": 8638 },
{ "date": "2024-05-28", "steps": 9381 },
{ "date": "2024-05-29", "steps": 10124 },
{ "date": "2024-05-30", "steps": 10867 },
{ "date": "2024-05-31", "steps": 9208 },
{ "date": "2024-06-01", "steps": 12949 },
{ "date": "2024-06-02", "steps": 10689 },
{ "date": "2024-06-03", "steps": 9029 },
{ "date": "2024-06-04", "steps": 9768 },
{ "date": "2024-06-05", "steps": 10506 },
{ "date": "2024-06-06", "steps": 8844 },
{ "date": "2024-06-07", "steps": 9581 },
{ "date": "2024-06-08", "steps": 13317 },
{ "date": "2024-06-09", "steps": 11053 },
{ "date": "2024-06-10", "steps": 9388 },
{ "date": "2024-06-11", "steps": 10122 },
{ "date": "2024-06-12", "steps": 10856 },
{ "date": "2024-06-13", "steps": 9189 },
{ "date": "2024-06-14", "steps": 9921 },
{ "date": "2024-06-15", "steps": 13652 },
{ "date": "2024-06-16", "steps": 8983 },
{ "date": "2024-06-17", "steps": 9713 },
{ "date": "2024-06-18", "steps": 10443 },
{ "date": "2024-06-19", "steps": 11171 },
{ "date": "2024-06-20", "steps": 9499 },
{ "date": "2024-06-21", "steps": 10226 },
{ "date": "2024-06-22", "steps": 13953 },
{ "date": "2024-06-23", "steps": 9279 },
{ "date": "2024-06-24", "steps": 10004 },
{ "date": "2024-06-25", "steps": 10728 },
{ "date": "2024-06-26", "steps": 9051 },
{ "date": "2024-06-27", "steps": 9774 },
{ "date": "2024-06-28", "steps": 10496 },
{ "date": "2024-06-29", "steps": 14217 },
{ "date": "2024-06-30", "steps": 9538 },
{ "date": "2024-07-01", "steps": 10258 },
{ "date": "2024-07-02", "steps": 10977 },
{ "date": "2024-07-03", "steps": 9295 },
{ "date": "2024-07-04", "steps": 10013 },
{ "date": "2024-07-05", "steps": 10730 },
{ "date": "2024-07-06", "steps": 12046 },
{ "date": "2024-07-07", "steps": 9761 },
{ "date": "2024-07-08", "steps": 10476 },
{ "date": "2024-07-09", "steps": 11190 },
{ "date": "2024-07-10", "steps": 9503 },
{ "date": "2024-07-11", "steps": 10216 },
{ "date": "2024-07-12", "steps": 10927 },
{ "date": "2024-07-13", "steps": 12238 },
{ "date": "2024-07-14", "steps": 9949 },
{ "date": "2024-07-15", "steps": 10658 },
{ "date": "2024-07-16", "steps": 8967 },
{ "date": "2024-07-17", "steps": 9675 },
{ "date": "2024-07-18", "steps": 10382 },
{ "date": "2024-07-19", "steps": 11089 },
{ "date": "2024-07-20", "steps": 12395 },
{ "date": "2024-07-21", "steps": 10100 },
{ "date": "2024-07-22", "steps": 10805 },
{ "date": "2024-07-23", "steps": 9109 },
{ "date": "2024-07-24", "steps": 9812 },
{ "date": "2024-07-25", "steps": 10515 },
{ "date": "2024-07-26", "steps": 8816 },
{ "date": "2024-07-27", "steps": 12518 },
{ "date": "2024-07-28", "steps": 10218 },
{ "date": "2024-07-29", "steps": 10918 },
{ "date": "2024-07-30", "steps": 9217 },
{ "date": "2024-07-31", "steps": 9916 },
{ "date": "2024-08-01", "steps": 10613 },
{ "date": "2024-08-02", "steps": 8911 },
{ "date": "2024-08-03", "steps": 12607 },
{ "date": "2024-08-04", "steps": 10303 },
{ "date": "2024-08-05", "steps": 8598 },
{ "date": "2024-08-06", "steps": 9293 },
{ "date": "2024-08-07", "steps": 9987 },
{ "date": "2024-08-08", "steps": 10681 },
{ "date": "2024-08-09", "steps": 8974 },
{ "date": "2024-08-10", "steps": 12666 },
{ "date": "2024-08-11", "steps": 10358 },
{ "date": "2024-08-12", "steps": 8649 },
{ "date": "2024-08-13", "steps": 9340 },
{ "date": "2024-08-14", "steps": 10030 },
{ "date": "2024-08-15", "steps": 8319 },
{ "date": "2024-08-16", "steps": 9008 },
{ "date": "2024-08-17", "steps": 12697 },
{ "date": "2024-08-18", "steps": 10385 },
{ "date": "2024-08-19", "steps": 8672 },
{ "date": "2024-08-20", "steps": 9359 },
{ "date": "2024-08-21", "steps": 10046 },
{ "date": "2024-08-22", "steps": 8332 },
{ "date": "2024-08-23", "steps": 9017 },
{ "date": "2024-08-24", "steps": 12702 },
{ "date": "2024-08-25", "steps": 7987 },
{ "date": "2024-08-26", "steps": 8671 },
{ "date": "2024-08-27", "steps": 9355 },
{ "date": "2024-08-28", "steps": 10038 },
{ "date": "2024-08-29", "steps": 8321 },
{ "date": "2024-08-30", "steps": 9003 },
{ "date": "2024-08-31", "steps": 12686 },
{ "date": "2024-09-01", "steps": 7967 },
{ "date": "2024-09-02", "steps": 8649 },
{ "date": "2024-09-03", "steps": 9330 },
{ "date": "2024-09-04", "steps": 10010 },
{ "date": "2024-09-05", "steps": 8291 },
{ "date": "2024-09-06", "steps": 8971 },
{ "date": "2024-09-07", "steps": 12651 },
{ "date": "2024-09-08", "steps": 7930 },
{ "date": "2024-09-09", "steps": 8609 },
{ "date": "2024-09-10", "steps": 9288 },
{ "date": "2024-09-11", "steps": 7567 },
{ "date": "2024-09-12", "steps": 8245 },
{ "date": "2024-09-13", "steps": 8923 },
{ "date": "2024-09-14", "steps": 12601 },
{ "date": "2024-09-15", "steps": 7879 },
{ "date": "2024-09-16", "steps": 8556 },
{ "date": "2024-09-17", "steps": 9234 },
{ "date": "2024-09-18", "steps": 7511 },
{ "date": "2024-09-19", "steps": 8188 },
{ "date": "2024-09-20", "steps": 8865 },
{ "date": "2024-09-21", "steps": 10141 },
{ "date": "2024-09-22", "steps": 7818 },
{ "date": "2024-09-23", "steps": 8494 },
{ "date": "2024-09-24", "steps": 9171 },
{ "date": "2024-09-25", "steps": 7447 },
{ "date": "2024-09-26", "steps": 8123 },
{ "date": "2024-09-27", "steps": 8799 },
{ "date": "2024-09-28", "steps": 10075 },
{ "date": "2024-09-29", "steps": 7751 },
{ "date": "2024-09-30", "steps": 8427 },
{ "date": "2024-10-01", "steps": 6703 },
{ "date": "2024-10-02", "steps": 7379 },
{ "date": "2024-10-03", "steps": 8055 },
{ "date": "2024-10-04", "steps": 8731 },
{ "date": "2024-10-05", "steps": 10007 },
{ "date": "2024-10-06", "steps": 7684 },
{ "date": "2024-10-07", "steps": 8360 },
{ "date": "2024-10-08", "steps": 6636 },
{ "date": "2024-10-09", "steps": 7312 },
{ "date": "2024-10-10", "steps": 7989 },
{ "date": "2024-10-11", "steps": 6265 },
{ "date": "2024-10-12", "steps": 9942 },
{ "date": "2024-10-13", "steps": 7619 },
{ "date": "2024-10-14", "steps": 8296 },
{ "date": "2024-10-15", "steps": 6573 },
{ "date": "2024-10-16", "steps": 7250 },
{ "date": "2024-10-17", "steps": 7928 },
{ "date": "2024-10-18", "steps": 6206 },
{ "date": "2024-10-19", "steps": 9884 },
{ "date": "2024-10-20", "steps": 7562 },
{ "date": "2024-10-21", "steps": 5840 },
{ "date": "2024-10-22", "steps": 6519 },
{ "date": "2024-10-23", "steps": 7198 },
{ "date": "2024-10-24", "steps": 7877 },
{ "date": "2024-10-25", "steps": 6156 },
{ "date": "2024-10-26", "steps": 9836 },
{ "date": "2024-10-27", "steps": 7516 },
{ "date": "2024-10-28", "steps": 5797 },
{ "date": "2024-10-29", "steps": 6477 },
{ "date": "2024-10-30", "steps": 7159 },
{ "date": "2024-10-31", "steps": 5440 },
{ "date": "2024-11-01", "steps": 6122 },
{ "date": "2024-11-02", "steps": 9804 },
{ "date": "2024-11-03", "steps": 7487 },
{ "date": "2024-11-04", "steps": 5770 },
{ "date": "2024-11-05", "steps": 6453 },
{ "date": "2024-11-06", "steps": 7137 },
{ "date": "2024-11-07", "steps": 5421 },
{ "date": "2024-11-08", "steps": 6106 },
{ "date": "2024-11-09", "steps": 9791 },
{ "date": "2024-11-10", "steps": 5076 },
{ "date": "2024-11-11", "steps": 5762 },
{ "date": "2024-11-12", "steps": 6449 },
{ "date": "2024-11-13", "steps": 7136 },
{ "date": "2024-11-14", "steps": 5423 },
{ "date": "2024-11-15", "steps": 6111 },
{ "date": "2024-11-16", "steps": 9800 },
{ "date": "2024-11-17", "steps": 5089 },
{ "date": "2024-11-18", "steps": 5779 },
{ "date": "2024-11-19", "steps": 6469 },
{ "date": "2024-11-20", "steps": 4759 },
{ "date": "2024-11-21", "steps": 5451 },
{ "date": "2024-11-22", "steps": 6143 },
{ "date": "2024-11-23", "steps": 9835 },
{ "date": "2024-11-24", "steps": 5128 },
{ "date": "2024-11-25", "steps": 5822 },
{ "date": "2024-11-26", "steps": 6516 },
{ "date": "2024-11-27", "steps": 4811 },
{ "date": "2024-11-28", "steps": 5506 },
{ "date": "2024-11-29", "steps": 6202 },
{ "date": "2024-11-30", "steps": 7499 },
{ "date": "2024-12-01", "steps": 5196 },
{ "date": "2024-12-02", "steps": 5894 },
{ "date": "2024-12-03", "steps": 6592 },
{ "date": "2024-12-04", "steps": 4892 },
{ "date": "2024-12-05", "steps": 5592 },
{ "date": "2024-12-06", "steps": 6292 },
{ "date": "2024-12-07", "steps": 7593 },
{ "date": "2024-12-08", "steps": 5295 },
{ "date": "2024-12-09", "steps": 5998 },
{ "date": "2024-12-10", "steps": 4301 },
{ "date": "2024-12-11", "steps": 5005 },
{ "date": "2024-12-12", "steps": 5710 },
{ "date": "2024-12-13", "steps": 6415 },
{ "date": "2024-12-14", "steps": 7721 },
{ "date": "2024-12-15", "steps": 5428 },
{ "date": "2024-12-16", "steps": 6136 },
{ "date": "2024-12-17", "steps": 4444 },
{ "date": "2024-12-18", "steps": 5153 },
{ "date": "2024-12-19", "steps": 5862 },
{ "date": "2024-12-20", "steps": 4173 },
{ "date": "2024-12-21", "steps": 7884 },
{ "date": "2024-12-22", "steps": 5596 },
{ "date": "2024-12-23", "steps": 6308 },
{ "date": "2024-12-24", "steps": 4621 },
{ "date": "2024-12-25", "steps": 5335 },
{ "date": "2024-12-26", "steps": 6050 },
{ "date": "2024-12-27", "steps": 4366 },
{ "date": "2024-12-28", "steps": 8082 },
{ "date": "2024-12-29", "steps": 5799 },
{ "date": "2024-12-30", "steps": 4117 },
{ "date": "2024-12-31", "steps": 4835 },
{ "date": "2025-01-01", "steps": 5554 },
{ "date": "2025-01-02", "steps": 6274 },
{ "date": "2025-01-03", "steps": 4595 },
{ "date": "2025-01-04", "steps": 8316 },
{ "date": "2025-01-05", "steps": 6038 },
{ "date": "2025-01-06", "steps": 4361 },
{ "date": "2025-01-07", "steps": 5085 },
{ "date": "2025-01-08", "steps": 5809 },
{ "date": "2025-01-09", "steps": 4134 },
{ "date": "2025-01-10", "steps": 4860 },
{ "date": "2025-01-11", "steps": 8587 },
{ "date": "2025-01-12", "steps": 6314 },
{ "date": "2025-01-13", "steps": 4642 },
{ "date": "2025-01-14", "steps": 5371 },
{ "date": "2025-01-15", "steps": 6100 },
{ "date": "2025-01-16", "steps": 4430 },
{ "date": "2025-01-17", "steps": 5161 },
{ "date": "2025-01-18", "steps": 8893 },
{ "date": "2025-01-19", "steps": 4225 },
{ "date": "2025-01-20", "steps": 4958 },
{ "date": "2025-01-21", "steps": 5692 },
{ "date": "2025-01-22", "steps": 6426 },
{ "date": "2025-01-23", "steps": 4761 },
{ "date": "2025-01-24", "steps": 5497 },
{ "date": "2025-01-25", "steps": 9233 },
{ "date": "2025-01-26", "steps": 4570 },
{ "date": "2025-01-27", "steps": 5308 },
{ "date": "2025-01-28", "steps": 6046 },
{ "date": "2025-01-29", "steps": 4386 },
{ "date": "2025-01-30", "steps": 5125 },
{ "date": "2025-01-31", "steps": 5866 },
{ "date": "2025-02-01", "steps": 9607 },
{ "date": "2025-02-02", "steps": 4948 },
{ "date": "2025-02-03", "steps": 5691 },
{ "date": "2025-02-04", "steps": 6434 },
{ "date": "2025-02-05", "steps": 4777 },
{ "date": "2025-02-06", "steps": 5521 },
{ "date": "2025-02-07", "steps": 6266 },
{ "date": "2025-02-08", "steps": 7611 },
{ "date": "2025-02-09", "steps": 5357 },
{ "date": "2025-02-10", "steps": 6104 },
{ "date": "2025-02-11", "steps": 6851 },
{ "date": "2025-02-12", "steps": 5198 },
{ "date": "2025-02-13", "steps": 5946 },
{ "date": "2025-02-14", "steps": 6695 },
{ "date": "2025-02-15", "steps": 8044 },
{ "date": "2025-02-16", "steps": 5794 },
{ "date": "2025-02-17", "steps": 6544 },
{ "date": "2025-02-18", "steps": 4895 },
{ "date": "2025-02-19", "steps": 5646 },
{ "date": "2025-02-20", "steps": 6398 },
{ "date": "2025-02-21", "steps": 7150 },
{ "date": "2025-02-22", "steps": 8503 },
{ "date": "2025-02-23", "steps": 6256 },
{ "date": "2025-02-24", "steps": 7009 },
{ "date": "2025-02-25", "steps": 5363 },
{ "date": "2025-02-26", "steps": 6118 },
{ "date": "2025-02-27", "steps": 6872 },
{ "date": "2025-02-28", "steps": 5228 },
{ "date": "2025-03-01", "steps": 8983 },
{ "date": "2025-03-02", "steps": 6739 },
{ "date": "2025-03-03", "steps": 7496 },
{ "date": "2025-03-04", "steps": 5852 },
{ "date": "2025-03-05", "steps": 6610 },
{ "date": "2025-03-06", "steps": 7367 },
{ "date": "2025-03-07", "steps": 5725 },
{ "date": "2025-03-08", "steps": 9483 },
{ "date": "2025-03-09", "steps": 7241 },
{ "date": "2025-03-10", "steps": 5600 },
{ "date": "2025-03-11", "steps": 6359 },
{ "date": "2025-03-12", "steps": 7118 },
{ "date": "2025-03-13", "steps": 7877 },
{ "date": "2025-03-14", "steps": 6237 },
{ "date": "2025-03-15", "steps": 9997 },
{ "date": "2025-03-16", "steps": 7757 },
{ "date": "2025-03-17", "steps": 6118 },
{ "date": "2025-03-18", "steps": 6878 },
{ "date": "2025-03-19", "steps": 7639 },
{ "date": "2025-03-20", "steps": 6000 },
{ "date": "2025-03-21", "steps": 6761 },
{ "date": "2025-03-22", "steps": 10522 },
{ "date": "2025-03-23", "steps": 8284 },
{ "date": "2025-03-24", "steps": 6645 },
{ "date": "2025-03-25", "steps": 7407 },
{ "date": "2025-03-26", "steps": 8168 },
{ "date": "2025-03-27", "steps": 6530 },
{ "date": "2025-03-28", "steps": 7292 },
{ "date": "2025-03-29", "steps": 11054 },
{ "date": "2025-03-30", "steps": 6416 },
{ "date": "2025-03-31", "steps": 7178 },
{ "date": "2025-04-01", "steps": 7940 },
{ "date": "2025-04-02", "steps": 8702 },
{ "date": "2025-04-03", "steps": 7064 },
{ "date": "2025-04-04", "steps": 7826 },
{ "date": "2025-04-05", "steps": 11588 },
{ "date": "2025-04-06", "steps": 6950 },
{ "date": "2025-04-07", "steps": 7712 },
{ "date": "2025-04-08", "steps": 8473 },
{ "date": "2025-04-09", "steps": 6835 },
{ "date": "2025-04-10", "steps": 7597 },
{ "date": "2025-04-11", "steps": 8358 },
{ "date": "2025-04-12", "steps": 12119 },
{ "date": "2025-04-13", "steps": 7481 },
{ "date": "2025-04-14", "steps": 8242 },
{ "date": "2025-04-15", "steps": 9003 },
{ "date": "2025-04-16", "steps": 7364 },
{ "date": "2025-04-17", "steps": 8124 },
{ "date": "2025-04-18", "steps": 8885 },
{ "date": "2025-04-19", "steps": 10245 },
{ "date": "2025-04-20", "steps": 8005 },
{ "date": "2025-04-21", "steps": 8764 },
{ "date": "2025-04-22", "steps": 9524 },
{ "date": "2025-04-23", "steps": 7883 },
{ "date": "2025-04-24", "steps": 8642 },
{ "date": "2025-04-25", "steps": 9401 },
{ "date": "2025-04-26", "steps": 10759 },
{ "date": "2025-04-27", "steps": 8517 },
{ "date": "2025-04-28", "steps": 9275 },
{ "date": "2025-04-29", "steps": 10033 },
{ "date": "2025-04-30", "steps": 8390 },
{ "date": "2025-05-01", "steps": 9147 },
{ "date": "2025-05-02", "steps": 9903 },
{ "date": "2025-05-03", "steps": 11259 },
{ "date": "2025-05-04", "steps": 9015 },
{ "date": "2025-05-05", "steps": 9770 },
{ "date": "2025-05-06", "steps": 8125 },
{ "date": "2025-05-07", "steps": 8879 },
{ "date": "2025-05-08", "steps": 9633 },
{ "date": "2025-05-09", "steps": 10387 },
{ "date": "2025-05-10", "steps": 11740 },
{ "date": "2025-05-11", "steps": 9493 },
{ "date": "2025-05-12", "steps": 10245 },
{ "date": "2025-05-13", "steps": 8597 },
{ "date": "2025-05-14", "steps": 9348 },
{ "date": "2025-05-15", "steps": 10099 },
{ "date": "2025-05-16", "steps": 8449 },
{ "date": "2025-05-17", "steps": 12199 },
{ "date": "2025-05-18", "steps": 9948 },
{ "date": "2025-05-19", "steps": 10697 },
{ "date": "2025-05-20", "steps": 9045 },
{ "date": "2025-05-21", "steps": 9793 },
{ "date": "2025-05-22", "steps": 10540 },
{ "date": "2025-05-23", "steps": 8887 },
{ "date": "2025-05-24", "steps": 12633 },
{ "date": "2025-05-25", "steps": 10378 },
{ "date": "2025-05-26", "steps": 8723 },
{ "date": "2025-05-27", "steps": 9467 },
{ "date": "2025-05-28", "steps": 10210 },
{ "date": "2025-05-29", "steps": 10953 },
{ "date": "2025-05-30", "steps": 9296 },
{ "date": "2025-05-31", "steps": 13037 },
{ "date": "2025-06-01", "steps": 10779 },
{ "date": "2025-06-02", "steps": 9119 },
{ "date": "2025-06-03", "steps": 9859 },
{ "date": "2025-06-04", "steps": 10598 },
{ "date": "2025-06-05", "steps": 8937 },
{ "date": "2025-06-06", "steps": 9674 },
{ "date": "2025-06-07", "steps": 13412 },
{ "date": "2025-06-08", "steps": 11148 },
{ "date": "2025-06-09", "steps": 9484 },
{ "date": "2025-06-10", "steps": 10219 },
{ "date": "2025-06-11", "steps": 10954 },
{ "date": "2025-06-12", "steps": 9287 },
{ "date": "2025-06-13", "steps": 10020 },
{ "date": "2025-06-14", "steps": 13753 },
{ "date": "2025-06-15", "steps": 9084 },
{ "date": "2025-06-16", "steps": 9815 },
{ "date": "2025-06-17", "steps": 10546 },
{ "date": "2025-06-18", "steps": 11275 },
{ "date": "2025-06-19", "steps": 9604 },
{ "date": "2025-06-20", "steps": 10332 },
{ "date": "2025-06-21", "steps": 14059 },
{ "date": "2025-06-22", "steps": 9386 },
{ "date": "2025-06-23", "steps": 10112 },
{ "date": "2025-06-24", "steps": 10837 },
{ "date": "2025-06-25", "steps": 9162 },
{ "date": "2025-06-26", "steps": 9885 },
{ "date": "2025-06-27", "steps": 10608 },
{ "date": "2025-06-28", "steps": 14330 },
{ "date": "2025-06-29", "steps": 9652 },
{ "date": "2025-06-30", "steps": 10373 },
{ "date": "2025-07-01", "steps": 11093 },
{ "date": "2025-07-02", "steps": 9412 },
{ "date": "2025-07-03", "steps": 10131 },
{ "date": "2025-07-04", "steps": 10848 },
{ "date": "2025-07-05", "steps": 12165 },
{ "date": "2025-07-06", "steps": 9882 },
{ "date": "2025-07-07", "steps": 10597 },
{ "date": "2025-07-08", "steps": 11312 },
{ "date": "2025-07-09", "steps": 9626 },
{ "date": "2025-07-10", "steps": 10340 },
{ "date": "2025-07-11", "steps": 11052 },
{ "date": "2025-07-12", "steps": 12364 },
{ "date": "2025-07-13", "steps": 10075 },
{ "date": "2025-07-14", "steps": 10786 },
{ "date": "2025-07-15", "steps": 9096 },
{ "date": "2025-07-16", "steps": 9805 },
{ "date": "2025-07-17", "steps": 10513 },
{ "date": "2025-07-18", "steps": 11220 },
{ "date": "2025-07-19", "steps": 12527 },
{ "date": "2025-07-20", "steps": 10233 },
{ "date": "2025-07-21", "steps": 10939 },
{ "date": "2025-07-22", "steps": 9244 },
{ "date": "2025-07-23", "steps": 9948 },
{ "date": "2025-07-24", "steps": 10651 },
{ "date": "2025-07-25", "steps": 8954 },
{ "date": "2025-07-26", "steps": 12656 },
{ "date": "2025-07-27", "steps": 10357 },
{ "date": "2025-07-28", "steps": 11058 },
{ "date": "2025-07-29", "steps": 9358 },
{ "date": "2025-07-30", "steps": 10057 },
{ "date": "2025-07-31", "steps": 10756 },
{ "date": "2025-08-01", "steps": 9054 },
{ "date": "2025-08-02", "steps": 12751 },
{ "date": "2025-08-03", "steps": 10448 },
{ "date": "2025-08-04", "steps": 8744 },
{ "date": "2025-08-05", "steps": 9439 },
{ "date": "2025-08-06", "steps": 10134 },
{ "date": "2025-08-07", "steps": 10829 },
{ "date": "2025-08-08", "steps": 9122 },
{ "date": "2025-08-09", "steps": 12815 },
{ "date": "2025-08-10", "steps": 10508 },
{ "date": "2025-08-11", "steps": 8800 },
{ "date": "2025-08-12", "steps": 9491 },
{ "date": "2025-08-13", "steps": 10182 },
{ "date": "2025-08-14", "steps": 8472 },
{ "date": "2025-08-15", "steps": 9162 },
{ "date": "2025-08-16", "steps": 12851 },
{ "date": "2025-08-17", "steps": 10539 },
{ "date": "2025-08-18", "steps": 8828 },
{ "date": "2025-08-19", "steps": 9515 },
{ "date": "2025-08-20", "steps": 10202 },
{ "date": "2025-08-21", "steps": 8489 },
{ "date": "2025-08-22", "steps": 9175 },
{ "date": "2025-08-23", "steps": 12861 },
{ "date": "2025-08-24", "steps": 8146 },
{ "date": "2025-08-25", "steps": 8830 },
{ "date": "2025-08-26", "steps": 9515 },
{ "date": "2025-08-27", "steps": 10199 },
{ "date": "2025-08-28", "steps": 8482 },
{ "date": "2025-08-29", "steps": 9165 },
{ "date": "2025-08-30", "steps": 12848 },
{ "date": "2025-08-31", "steps": 8130 },
{ "date": "2025-09-01", "steps": 8812 },
{ "date": "2025-09-02", "steps": 9493 },
{ "date": "2025-09-03", "steps": 7774 },
{ "date": "2025-09-04", "steps": 8455 },
{ "date": "2025-09-05", "steps": 9136 },
{ "date": "2025-09-06", "steps": 12816 },
{ "date": "2025-09-07", "steps": 8095 },
{ "date": "2025-09-08", "steps": 8775 },
{ "date": "2025-09-09", "steps": 9454 },
{ "date": "2025-09-10", "steps": 7733 },
{ "date": "2025-09-11", "steps": 8412 },
{ "date": "2025-09-12", "steps": 9090 },
{ "date": "2025-09-13", "steps": 10368 },
{ "date": "2025-09-14", "steps": 8046 },
{ "date": "2025-09-15", "steps": 8724 },
{ "date": "2025-09-16", "steps": 9402 },
{ "date": "2025-09-17", "steps": 7679 },
{ "date": "2025-09-18", "steps": 8356 },
{ "date": "2025-09-19", "steps": 9033 },
{ "date": "2025-09-20", "steps": 10310 },
{ "date": "2025-09-21", "steps": 7987 },
{ "date": "2025-09-22", "steps": 8663 },
{ "date": "2025-09-23", "steps": 6940 },
{ "date": "2025-09-24", "steps": 7616 },
{ "date": "2025-09-25", "steps": 8293 },
{ "date": "2025-09-26", "steps": 8969 },
{ "date": "2025-09-27", "steps": 10245 },
{ "date": "2025-09-28", "steps": 7921 },
{ "date": "2025-09-29", "steps": 8597 },
{ "date": "2025-09-30", "steps": 6873 },
{ "date": "2025-10-01", "steps": 7549 },
{ "date": "2025-10-02", "steps": 8225 },
{ "date": "2025-10-03", "steps": 6501 },
{ "date": "2025-10-04", "steps": 10177 },
{ "date": "2025-10-05", "steps": 7853 },
{ "date": "2025-10-06", "steps": 8529 },
{ "date": "2025-10-07", "steps": 6805 },
{ "date": "2025-10-08", "steps": 7482 },
{ "date": "2025-10-09", "steps": 8158 },
{ "date": "2025-10-10", "steps": 6434 },
{ "date": "2025-10-11", "steps": 10111 },
{ "date": "2025-10-12", "steps": 7788 },
{ "date": "2025-10-13", "steps": 6064 },
{ "date": "2025-10-14", "steps": 6741 },
{ "date": "2025-10-15", "steps": 7419 },
{ "date": "2025-10-16", "steps": 8096 },
{ "date": "2025-10-17", "steps": 6373 },
{ "date": "2025-10-18", "steps": 10051 },
{ "date": "2025-10-19", "steps": 7729 },
{ "date": "2025-10-20", "steps": 6007 },
{ "date": "2025-10-21", "steps": 6685 },
{ "date": "2025-10-22", "steps": 7364 },
{ "date": "2025-10-23", "steps": 5643 },
{ "date": "2025-10-24", "steps": 6322 },
{ "date": "2025-10-25", "steps": 10001 },
{ "date": "2025-10-26", "steps": 7681 },
{ "date": "2025-10-27", "steps": 5961 },
{ "date": "2025-10-28", "steps": 6641 },
{ "date": "2025-10-29", "steps": 7322 },
{ "date": "2025-10-30", "steps": 5603 },
{ "date": "2025-10-31", "steps": 6284 },
{ "date": "2025-11-01", "steps": 9966 },
{ "date": "2025-11-02", "steps": 5248 },
{ "date": "2025-11-03", "steps": 5931 },
{ "date": "2025-11-04", "steps": 6613 },
{ "date": "2025-11-05", "steps": 7297 },
{ "date": "2025-11-06", "steps": 5580 },
{ "date": "2025-11-07", "steps": 6265 },
{ "date": "2025-11-08", "steps": 9949 },
{ "date": "2025-11-09", "steps": 5234 },
{ "date": "2025-11-10", "steps": 5920 },
{ "date": "2025-11-11", "steps": 6605 },
{ "date": "2025-11-12", "steps": 4892 },
{ "date": "2025-11-13", "steps": 5579 },
{ "date": "2025-11-14", "steps": 6266 },
{ "date": "2025-11-15", "steps": 9954 },
{ "date": "2025-11-16", "steps": 5242 },
{ "date": "2025-11-17", "steps": 5931 },
{ "date": "2025-11-18", "steps": 6621 },
{ "date": "2025-11-19", "steps": 4911 },
{ "date": "2025-11-20", "steps": 5601 },
{ "date": "2025-11-21", "steps": 6293 },
{ "date": "2025-11-22", "steps": 7584 },
{ "date": "2025-11-23", "steps": 5277 },
{ "date": "2025-11-24", "steps": 5969 },
{ "date": "2025-11-25", "steps": 6663 },
{ "date": "2025-11-26", "steps": 4957 },
{ "date": "2025-11-27", "steps": 5652 },
{ "date": "2025-11-28", "steps": 6347 },
{ "date": "2025-11-29", "steps": 7643 },
{ "date": "2025-11-30", "steps": 5339 },
{ "date": "2025-12-01", "steps": 6036 },
{ "date": "2025-12-02", "steps": 4334 },
{ "date": "2025-12-03", "steps": 5032 },
{ "date": "2025-12-04", "steps": 5732 },
{ "date": "2025-12-05", "steps": 6431 },
{ "date": "2025-12-06", "steps": 7732 },
{ "date": "2025-12-07", "steps": 5433 },
{ "date": "2025-12-08", "steps": 6135 },
{ "date": "2025-12-09", "steps": 4437 },
{ "date": "2025-12-10", "steps": 5140 },
{ "date": "2025-12-11", "steps": 5844 },
{ "date": "2025-12-12", "steps": 4148 },
{ "date": "2025-12-13", "steps": 7854 },
{ "date": "2025-12-14", "steps": 5559 },
{ "date": "2025-12-15", "steps": 6266 },
{ "date": "2025-12-16", "steps": 4573 },
{ "date": "2025-12-17", "steps": 5281 },
{ "date": "2025-12-18", "steps": 5990 },
{ "date": "2025-12-19", "steps": 4300 },
{ "date": "2025-12-20", "steps": 8010 },
{ "date": "2025-12-21", "steps": 5721 },
{ "date": "2025-12-22", "steps": 6432 },
{ "date": "2025-12-23", "steps": 4745 },
{ "date": "2025-12-24", "steps": 5458 },
{ "date": "2025-12-25", "steps": 6172 },
{ "date": "2025-12-26", "steps": 4486 },
{ "date": "2025-12-27", "steps": 8201 },
{ "date": "2025-12-28", "steps": 5918 },
{ "date": "2025-12-29", "steps": 4234 },
{ "date": "2025-12-30", "steps": 4952 },
{ "date": "2025-12-31", "steps": 5670 },
{ "date": "2026-01-01", "steps": 6389 },
{ "date": "2026-01-02", "steps": 4709 },
{ "date": "2026-01-03", "steps": 8429 },
{ "date": "2026-01-04", "steps": 6151 },
{ "date": "2026-01-05", "steps": 4472 },
{ "date": "2026-01-06", "steps": 5195 },
{ "date": "2026-01-07", "steps": 5919 },
{ "date": "2026-01-08", "steps": 4243 },
{ "date": "2026-01-09", "steps": 4968 },
{ "date": "2026-01-10", "steps": 8693 },
{ "date": "2026-01-11", "steps": 6420 },
{ "date": "2026-01-12", "steps": 4747 },
{ "date": "2026-01-13", "steps": 5475 },
{ "date": "2026-01-14", "steps": 6203 },
{ "date": "2026-01-15", "steps": 4532 },
{ "date": "2026-01-16", "steps": 5262 },
{ "date": "2026-01-17", "steps": 8993 },
{ "date": "2026-01-18", "steps": 4324 },
{ "date": "2026-01-19", "steps": 5057 },
{ "date": "2026-01-20", "steps": 5789 },
{ "date": "2026-01-21", "steps": 6523 },
{ "date": "2026-01-22", "steps": 4857 },
{ "date": "2026-01-23", "steps": 5592 },
{ "date": "2026-01-24", "steps": 9328 },
{ "date": "2026-01-25", "steps": 4664 },
{ "date": "2026-01-26", "steps": 5401 },
{ "date": "2026-01-27", "steps": 6138 },
{ "date": "2026-01-28", "steps": 4477 },
{ "date": "2026-01-29", "steps": 5215 },
{ "date": "2026-01-30", "steps": 5955 },
{ "date": "2026-01-31", "steps": 9695 },
{ "date": "2026-02-01", "steps": 5036 },
{ "date": "2026-02-02", "steps": 5778 },
{ "date": "2026-02-03", "steps": 6520 },
{ "date": "2026-02-04", "steps": 4863 },
{ "date": "2026-02-05", "steps": 5606 },
{ "date": "2026-02-06", "steps": 6350 },
{ "date": "2026-02-07", "steps": 7694 },
{ "date": "2026-02-08", "steps": 5440 },
{ "date": "2026-02-09", "steps": 6185 },
{ "date": "2026-02-10", "steps": 6932 },
{ "date": "2026-02-11", "steps": 5278 },
{ "date": "2026-02-12", "steps": 6026 },
{ "date": "2026-02-13", "steps": 6774 },
{ "date": "2026-02-14", "steps": 8122 },
{ "date": "2026-02-15", "steps": 5871 },
{ "date": "2026-02-16", "steps": 6621 },
{ "date": "2026-02-17", "steps": 4971 },
{ "date": "2026-02-18", "steps": 5722 },
{ "date": "2026-02-19", "steps": 6473 },
{ "date": "2026-02-20", "steps": 7224 },
{ "date": "2026-02-21", "steps": 8577 },
{ "date": "2026-02-22", "steps": 6329 },
{ "date": "2026-02-23", "steps": 7082 },
{ "date": "2026-02-24", "steps": 5436 },
{ "date": "2026-02-25", "steps": 6189 },
{ "date": "2026-02-26", "steps": 6944 },
{ "date": "2026-02-27", "steps": 5298 },
{ "date": "2026-02-28", "steps": 9054 },
{ "date": "2026-03-01", "steps": 6809 },
{ "date": "2026-03-02", "steps": 7565 },
{ "date": "2026-03-03", "steps": 5921 },
{ "date": "2026-03-04", "steps": 6678 },
{ "date": "2026-03-05", "steps": 7435 },
{ "date": "2026-03-06", "steps": 5792 },
{ "date": "2026-03-07", "steps": 9550 },
{ "date": "2026-03-08", "steps": 7308 },
{ "date": "2026-03-09", "steps": 5666 },
{ "date": "2026-03-10", "steps": 6425 },
{ "date": "2026-03-11", "steps": 7184 },
{ "date": "2026-03-12", "steps": 7943 },
{ "date": "2026-03-13", "steps": 6302 },
{ "date": "2026-03-14", "steps": 10062 },
{ "date": "2026-03-15", "steps": 7822 },
{ "date": "2026-03-16", "steps": 6182 },
{ "date": "2026-03-17", "steps": 6942 },
{ "date": "2026-03-18", "steps": 7703 },
{ "date": "2026-03-19", "steps": 6064 },
{ "date": "2026-03-20", "steps": 6824 },
{ "date": "2026-03-21", "steps": 10585 },
{ "date": "2026-03-22", "steps": 8347 },
{ "date": "2026-03-23", "steps": 6708 },
{ "date": "2026-03-24", "steps": 7469 },
{ "date": "2026-03-25", "steps": 8231 },
{ "date": "2026-03-26", "steps": 6593 },
{ "date": "2026-03-27", "steps": 7354 },
{ "date": "2026-03-28", "steps": 11116 },
{ "date": "2026-03-29", "steps": 6478 },
{ "date": "2026-03-30", "steps": 7240 },
{ "date": "2026-03-31", "steps": 8002 },
{ "date": "2026-04-01", "steps": 8764 },
{ "date": "2026-04-02", "steps": 7126 },
{ "date": "2026-04-03", "steps": 7888 },
{ "date": "2026-04-04", "steps": 11650 },
{ "date": "2026-04-05", "steps": 7012 },
{ "date": "2026-04-06", "steps": 7774 },
{ "date": "2026-04-07", "steps": 8536 },
{ "date": "2026-04-08", "steps": 6898 },
{ "date": "2026-04-09", "steps": 7659 },
{ "date": "2026-04-10", "steps": 8421 },
{ "date": "2026-04-11", "steps": 12182 },
{ "date": "2026-04-12", "steps": 7544 },
{ "date": "2026-04-13", "steps": 8305 },
{ "date": "2026-04-14", "steps": 9066 },
{ "date": "2026-04-15", "steps": 7427 },
{ "date": "2026-04-16", "steps": 8188 },
{ "date": "2026-04-17", "steps": 8949 },
{ "date": "2026-04-18", "steps": 10309 },
{ "date": "2026-04-19", "steps": 8069 },
{ "date": "2026-04-20", "steps": 8829 },
{ "date": "2026-04-21", "steps": 9589 },
{ "date": "2026-04-22", "steps": 7949 },
{ "date": "2026-04-23", "steps": 8708 },
{ "date": "2026-04-24", "steps": 9467 },
{ "date": "2026-04-25", "steps": 10826 },
{ "date": "2026-04-26", "steps": 8584 },
{ "date": "2026-04-27", "steps": 9343 },
{ "date": "2026-04-28", "steps": 7701 },
{ "date": "2026-04-29", "steps": 8458 },
{ "date": "2026-04-30", "steps": 9215 },
{ "date": "2026-05-01", "steps": 9972 },
{ "date": "2026-05-02", "steps": 11329 },
{ "date": "2026-05-03", "steps": 9085 },
{ "date": "2026-05-04", "steps": 9841 },
{ "date": "2026-05-05", "steps": 8196 },
{ "date": "2026-05-06", "steps": 8951 },
{ "date": "2026-05-07", "steps": 9706 },
{ "date": "2026-05-08", "steps": 8060 },
{ "date": "2026-05-09", "steps": 11813 },
{ "date": "2026-05-10", "steps": 9567 },
{ "date": "2026-05-11", "steps": 10320 },
{ "date": "2026-05-12", "steps": 8672 },
{ "date": "2026-05-13", "steps": 9424 },
{ "date": "2026-05-14", "steps": 10175 },
{ "date": "2026-05-15", "steps": 8526 },
{ "date": "2026-05-16", "steps": 12277 },
{ "date": "2026-05-17", "steps": 10026 },
{ "date": "2026-05-18", "steps": 8376 },
{ "date": "2026-05-19", "steps": 9125 },
{ "date": "2026-05-20", "steps": 9873 },
{ "date": "2026-05-21", "steps": 10621 },
{ "date": "2026-05-22", "steps": 8968 },
{ "date": "2026-05-23", "steps": 12715 },
{ "date": "2026-05-24", "steps": 10461 },
{ "date": "2026-05-25", "steps": 8806 },
{ "date": "2026-05-26", "steps": 9551 },
{ "date": "2026-05-27", "steps": 10296 },
{ "date": "2026-05-28", "steps": 8639 },
{ "date": "2026-05-29", "steps": 9382 },
{ "date": "2026-05-30", "steps": 13125 },
{ "date": "2026-05-31", "steps": 10867 },
{ "date": "2026-06-01", "steps": 9208 },
{ "date": "2026-06-02", "steps": 9949 },
{ "date": "2026-06-03", "steps": 10689 },
{ "date": "2026-06-04", "steps": 9028 },
{ "date": "2026-06-05", "steps": 9767 },
{ "date": "2026-06-06", "steps": 13505 },
{ "date": "2026-06-07", "steps": 8842 },
{ "date": "2026-06-08", "steps": 9579 },
{ "date": "2026-06-09", "steps": 10315 },
{ "date": "2026-06-10", "steps": 11050 },
{ "date": "2026-06-11", "steps": 9385 },
{ "date": "2026-06-12", "steps": 10119 },
{ "date": "2026-06-13", "steps": 13852 },
{ "date": "2026-06-14", "steps": 9184 },
{ "date": "2026-06-15", "steps": 9916 },
{ "date": "2026-06-16", "steps": 10647 },
{ "date": "2026-06-17", "steps": 8978 },
{ "date": "2026-06-18", "steps": 9708 },
{ "date": "2026-06-19", "steps": 10437 },
{ "date": "2026-06-20", "steps": 14165 },
{ "date": "2026-06-21", "steps": 9492 },
{ "date": "2026-06-22", "steps": 10219 },
{ "date": "2026-06-23", "steps": 10945 },
{ "date": "2026-06-24", "steps": 9271 },
{ "date": "2026-06-25", "steps": 9995 },
{ "date": "2026-06-26", "steps": 10719 },
{ "date": "2026-06-27", "steps": 12042 },
{ "date": "2026-06-28", "steps": 9765 },
{ "date": "2026-06-29", "steps": 10486 },
{ "date": "2026-06-30", "steps": 11207 },
{ "date": "2026-07-01", "steps": 9528 },
{ "date": "2026-07-02", "steps": 10247 },
{ "date": "2026-07-03", "steps": 10966 },
{ "date": "2026-07-04", "steps": 12284 },
{ "date": "2026-07-05", "steps": 10001 },
{ "date": "2026-07-06", "steps": 10717 },
{ "date": "2026-07-07", "steps": 9033 },
{ "date": "2026-07-08", "steps": 9748 },
{ "date": "2026-07-09", "steps": 10463 },
{ "date": "2026-07-10", "steps": 11176 },
{ "date": "2026-07-11", "steps": 12489 },
{ "date": "2026-07-12", "steps": 10201 },
{ "date": "2026-07-13", "steps": 10912 },
{ "date": "2026-07-14", "steps": 9223 },
{ "date": "2026-07-15", "steps": 9933 },
{ "date": "2026-07-16", "steps": 10642 },
{ "date": "2026-07-17", "steps": 8951 },
{ "date": "2026-07-18", "steps": 12658 },
{ "date": "2026-07-19", "steps": 10365 },
{ "date": "2026-07-20", "steps": 11072 },
{ "date": "2026-07-21", "steps": 9377 },
{ "date": "2026-07-22", "steps": 10082 },
{ "date": "2026-07-23", "steps": 10787 },
{ "date": "2026-07-24", "steps": 9090 },
{ "date": "2026-07-25", "steps": 12793 },
{ "date": "2026-07-26", "steps": 10495 },
{ "date": "2026-07-27", "steps": 8797 },
{ "date": "2026-07-28", "steps": 9497 },
{ "date": "2026-07-29", "steps": 10198 },
{ "date": "2026-07-30", "steps": 10897 },
{ "date": "2026-07-31", "steps": 9196 },
{ "date": "2026-08-01", "steps": 12894 },
{ "date": "2026-08-02", "steps": 10592 },
{ "date": "2026-08-03", "steps": 8888 },
{ "date": "2026-08-04", "steps": 9585 },
{ "date": "2026-08-05", "steps": 10280 },
{ "date": "2026-08-06", "steps": 8575 },
{ "date": "2026-08-07", "steps": 9270 },
{ "date": "2026-08-08", "steps": 12964 },
{ "date": "2026-08-09", "steps": 10657 },
{ "date": "2026-08-10", "steps": 8950 },
{ "date": "2026-08-11", "steps": 9642 },
{ "date": "2026-08-12", "steps": 10333 },
{ "date": "2026-08-13", "steps": 8624 },
{ "date": "2026-08-14", "steps": 9314 },
{ "date": "2026-08-15", "steps": 13004 },
{ "date": "2026-08-16", "steps": 8293 },
{ "date": "2026-08-17", "steps": 8982 },
{ "date": "2026-08-18", "steps": 9670 },
{ "date": "2026-08-19", "steps": 10358 },
{ "date": "2026-08-20", "steps": 8645 },
{ "date": "2026-08-21", "steps": 9332 },
{ "date": "2026-08-22", "steps": 13018 },
{ "date": "2026-08-23", "steps": 8304 },
{ "date": "2026-08-24", "steps": 8989 },
{ "date": "2026-08-25", "steps": 9674 },
{ "date": "2026-08-26", "steps": 10358 },
{ "date": "2026-08-27", "steps": 8642 },
{ "date": "2026-08-28", "steps": 9326 },
{ "date": "2026-08-29", "steps": 13009 },
{ "date": "2026-08-30", "steps": 8292 },
{ "date": "2026-08-31", "steps": 8974 },
{ "date": "2026-09-01", "steps": 9656 },
{ "date": "2026-09-02", "steps": 7938 },
{ "date": "2026-09-03", "steps": 8619 },
{ "date": "2026-09-04", "steps": 9300 },
{ "date": "2026-09-05", "steps": 12980 },
{ "date": "2026-09-06", "steps": 8260 },
{ "date": "2026-09-07", "steps": 8940 },
{ "date": "2026-09-08", "steps": 9620 },
{ "date": "2026-09-09", "steps": 7899 },
{ "date": "2026-09-10", "steps": 8578 },
{ "date": "2026-09-11", "steps": 9257 },
{ "date": "2026-09-12", "steps": 10535 },
{ "date": "2026-09-13", "steps": 8214 },
{ "date": "2026-09-14", "steps": 8892 },
{ "date": "2026-09-15", "steps": 9570 },
{ "date": "2026-09-16", "steps": 7847 },
{ "date": "2026-09-17", "steps": 8525 },
{ "date": "2026-09-18", "steps": 9202 },
{ "date": "2026-09-19", "steps": 10479 },
{ "date": "2026-09-20", "steps": 8156 },
{ "date": "2026-09-21", "steps": 8832 },
{ "date": "2026-09-22", "steps": 7109 },
{ "date": "2026-09-23", "steps": 7786 },
{ "date": "2026-09-24", "steps": 8462 },
{ "date": "2026-09-25", "steps": 9138 },
{ "date": "2026-09-26", "steps": 10415 },
{ "date": "2026-09-27", "steps": 8091 },
{ "date": "2026-09-28", "steps": 8767 },
{ "date": "2026-09-29", "steps": 7043 },
{ "date": "2026-09-30", "steps": 7719 },
];
export function Example() {
return (
);
}
```
#### One year
A single year makes one turn: weekday rhythm shows as a fine comb, bursts as long bars.
```tsx
'use client';
import { SpiralYearCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';
const yearContributions = [
{ "date": "2025-10-08", "commits": 0 },
{ "date": "2025-10-09", "commits": 1 },
{ "date": "2025-10-10", "commits": 2 },
{ "date": "2025-10-11", "commits": 3 },
{ "date": "2025-10-12", "commits": 0 },
{ "date": "2025-10-13", "commits": 0 },
{ "date": "2025-10-14", "commits": 0 },
{ "date": "2025-10-15", "commits": 5 },
{ "date": "2025-10-16", "commits": 2 },
{ "date": "2025-10-17", "commits": 4 },
{ "date": "2025-10-18", "commits": 6 },
{ "date": "2025-10-19", "commits": 7 },
{ "date": "2025-10-20", "commits": 0 },
{ "date": "2025-10-21", "commits": 0 },
{ "date": "2025-10-22", "commits": 5 },
{ "date": "2025-10-23", "commits": 6 },
{ "date": "2025-10-24", "commits": 2 },
{ "date": "2025-10-25", "commits": 2 },
{ "date": "2025-10-26", "commits": 2 },
{ "date": "2025-10-27", "commits": 0 },
{ "date": "2025-10-28", "commits": 0 },
{ "date": "2025-10-29", "commits": 1 },
{ "date": "2025-10-30", "commits": 2 },
{ "date": "2025-10-31", "commits": 3 },
{ "date": "2025-11-01", "commits": 0 },
{ "date": "2025-11-02", "commits": 1 },
{ "date": "2025-11-03", "commits": 0 },
{ "date": "2025-11-04", "commits": 0 },
{ "date": "2025-11-05", "commits": 0 },
{ "date": "2025-11-06", "commits": 1 },
{ "date": "2025-11-07", "commits": 2 },
{ "date": "2025-11-08", "commits": 3 },
{ "date": "2025-11-09", "commits": 0 },
{ "date": "2025-11-10", "commits": 3 },
{ "date": "2025-11-11", "commits": 0 },
{ "date": "2025-11-12", "commits": 3 },
{ "date": "2025-11-13", "commits": 0 },
{ "date": "2025-11-14", "commits": 1 },
{ "date": "2025-11-15", "commits": 2 },
{ "date": "2025-11-16", "commits": 4 },
{ "date": "2025-11-17", "commits": 0 },
{ "date": "2025-11-18", "commits": 0 },
{ "date": "2025-11-19", "commits": 6 },
{ "date": "2025-11-20", "commits": 8 },
{ "date": "2025-11-21", "commits": 6 },
{ "date": "2025-11-22", "commits": 7 },
{ "date": "2025-11-23", "commits": 8 },
{ "date": "2025-11-24", "commits": 0 },
{ "date": "2025-11-25", "commits": 0 },
{ "date": "2025-11-26", "commits": 5 },
{ "date": "2025-11-27", "commits": 5 },
{ "date": "2025-11-28", "commits": 5 },
{ "date": "2025-11-29", "commits": 1 },
{ "date": "2025-11-30", "commits": 2 },
{ "date": "2025-12-01", "commits": 0 },
{ "date": "2025-12-02", "commits": 3 },
{ "date": "2025-12-03", "commits": 0 },
{ "date": "2025-12-04", "commits": 1 },
{ "date": "2025-12-05", "commits": 2 },
{ "date": "2025-12-06", "commits": 3 },
{ "date": "2025-12-07", "commits": 0 },
{ "date": "2025-12-08", "commits": 0 },
{ "date": "2025-12-09", "commits": 0 },
{ "date": "2025-12-10", "commits": 3 },
{ "date": "2025-12-11", "commits": 1 },
{ "date": "2025-12-12", "commits": 2 },
{ "date": "2025-12-13", "commits": 3 },
{ "date": "2025-12-14", "commits": 5 },
{ "date": "2025-12-15", "commits": 0 },
{ "date": "2025-12-16", "commits": 0 },
{ "date": "2025-12-17", "commits": 4 },
{ "date": "2025-12-18", "commits": 5 },
{ "date": "2025-12-19", "commits": 1 },
{ "date": "2025-12-20", "commits": 2 },
{ "date": "2025-12-21", "commits": 2 },
{ "date": "2025-12-22", "commits": 0 },
{ "date": "2025-12-23", "commits": 0 },
{ "date": "2025-12-24", "commits": 1 },
{ "date": "2025-12-25", "commits": 2 },
{ "date": "2025-12-26", "commits": 3 },
{ "date": "2025-12-27", "commits": 0 },
{ "date": "2025-12-28", "commits": 1 },
{ "date": "2025-12-29", "commits": 0 },
{ "date": "2025-12-30", "commits": 0 },
{ "date": "2025-12-31", "commits": 0 },
{ "date": "2026-01-01", "commits": 1 },
{ "date": "2026-01-02", "commits": 2 },
{ "date": "2026-01-03", "commits": 3 },
{ "date": "2026-01-04", "commits": 0 },
{ "date": "2026-01-05", "commits": 0 },
{ "date": "2026-01-06", "commits": 0 },
{ "date": "2026-01-07", "commits": 3 },
{ "date": "2026-01-08", "commits": 0 },
{ "date": "2026-01-09", "commits": 1 },
{ "date": "2026-01-10", "commits": 2 },
{ "date": "2026-01-11", "commits": 3 },
{ "date": "2026-01-12", "commits": 0 },
{ "date": "2026-01-13", "commits": 0 },
{ "date": "2026-01-14", "commits": 6 },
{ "date": "2026-01-15", "commits": 8 },
{ "date": "2026-01-16", "commits": 7 },
{ "date": "2026-01-17", "commits": 9 },
{ "date": "2026-01-18", "commits": 10 },
{ "date": "2026-01-19", "commits": 0 },
{ "date": "2026-01-20", "commits": 0 },
{ "date": "2026-01-21", "commits": 7 },
{ "date": "2026-01-22", "commits": 7 },
{ "date": "2026-01-23", "commits": 7 },
{ "date": "2026-01-24", "commits": 3 },
{ "date": "2026-01-25", "commits": 3 },
{ "date": "2026-01-26", "commits": 3 },
{ "date": "2026-01-27", "commits": 0 },
{ "date": "2026-01-28", "commits": 0 },
{ "date": "2026-01-29", "commits": 1 },
{ "date": "2026-01-30", "commits": 2 },
{ "date": "2026-01-31", "commits": 3 },
{ "date": "2026-02-01", "commits": 0 },
{ "date": "2026-02-02", "commits": 0 },
{ "date": "2026-02-03", "commits": 0 },
{ "date": "2026-02-04", "commits": 3 },
{ "date": "2026-02-05", "commits": 0 },
{ "date": "2026-02-06", "commits": 1 },
{ "date": "2026-02-07", "commits": 2 },
{ "date": "2026-02-08", "commits": 3 },
{ "date": "2026-02-09", "commits": 0 },
{ "date": "2026-02-10", "commits": 0 },
{ "date": "2026-02-11", "commits": 3 },
{ "date": "2026-02-12", "commits": 4 },
{ "date": "2026-02-13", "commits": 1 },
{ "date": "2026-02-14", "commits": 2 },
{ "date": "2026-02-15", "commits": 2 },
{ "date": "2026-02-16", "commits": 0 },
{ "date": "2026-02-17", "commits": 3 },
{ "date": "2026-02-18", "commits": 1 },
{ "date": "2026-02-19", "commits": 2 },
{ "date": "2026-02-20", "commits": 3 },
{ "date": "2026-02-21", "commits": 0 },
{ "date": "2026-02-22", "commits": 1 },
{ "date": "2026-02-23", "commits": 0 },
{ "date": "2026-02-24", "commits": 0 },
{ "date": "2026-02-25", "commits": 0 },
{ "date": "2026-02-26", "commits": 1 },
{ "date": "2026-02-27", "commits": 2 },
{ "date": "2026-02-28", "commits": 3 },
{ "date": "2026-03-01", "commits": 0 },
{ "date": "2026-03-02", "commits": 0 },
{ "date": "2026-03-03", "commits": 0 },
{ "date": "2026-03-04", "commits": 3 },
{ "date": "2026-03-05", "commits": 0 },
{ "date": "2026-03-06", "commits": 1 },
{ "date": "2026-03-07", "commits": 2 },
{ "date": "2026-03-08", "commits": 3 },
{ "date": "2026-03-09", "commits": 0 },
{ "date": "2026-03-10", "commits": 0 },
{ "date": "2026-03-11", "commits": 5 },
{ "date": "2026-03-12", "commits": 8 },
{ "date": "2026-03-13", "commits": 7 },
{ "date": "2026-03-14", "commits": 10 },
{ "date": "2026-03-15", "commits": 12 },
{ "date": "2026-03-16", "commits": 0 },
{ "date": "2026-03-17", "commits": 0 },
{ "date": "2026-03-18", "commits": 10 },
{ "date": "2026-03-19", "commits": 10 },
{ "date": "2026-03-20", "commits": 9 },
{ "date": "2026-03-21", "commits": 5 },
{ "date": "2026-03-22", "commits": 4 },
{ "date": "2026-03-23", "commits": 0 },
{ "date": "2026-03-24", "commits": 0 },
{ "date": "2026-03-25", "commits": 0 },
{ "date": "2026-03-26", "commits": 1 },
{ "date": "2026-03-27", "commits": 2 },
{ "date": "2026-03-28", "commits": 3 },
{ "date": "2026-03-29", "commits": 0 },
{ "date": "2026-03-30", "commits": 0 },
{ "date": "2026-03-31", "commits": 0 },
{ "date": "2026-04-01", "commits": 3 },
{ "date": "2026-04-02", "commits": 0 },
{ "date": "2026-04-03", "commits": 1 },
{ "date": "2026-04-04", "commits": 2 },
{ "date": "2026-04-05", "commits": 3 },
{ "date": "2026-04-06", "commits": 0 },
{ "date": "2026-04-07", "commits": 0 },
{ "date": "2026-04-08", "commits": 2 },
{ "date": "2026-04-09", "commits": 3 },
{ "date": "2026-04-10", "commits": 0 },
{ "date": "2026-04-11", "commits": 1 },
{ "date": "2026-04-12", "commits": 2 },
{ "date": "2026-04-13", "commits": 3 },
{ "date": "2026-04-14", "commits": 0 },
{ "date": "2026-04-15", "commits": 1 },
{ "date": "2026-04-16", "commits": 2 },
{ "date": "2026-04-17", "commits": 3 },
{ "date": "2026-04-18", "commits": 0 },
{ "date": "2026-04-19", "commits": 1 },
{ "date": "2026-04-20", "commits": 0 },
{ "date": "2026-04-21", "commits": 0 },
{ "date": "2026-04-22", "commits": 0 },
{ "date": "2026-04-23", "commits": 1 },
{ "date": "2026-04-24", "commits": 2 },
{ "date": "2026-04-25", "commits": 3 },
{ "date": "2026-04-26", "commits": 0 },
{ "date": "2026-04-27", "commits": 0 },
{ "date": "2026-04-28", "commits": 0 },
{ "date": "2026-04-29", "commits": 3 },
{ "date": "2026-04-30", "commits": 0 },
{ "date": "2026-05-01", "commits": 1 },
{ "date": "2026-05-02", "commits": 2 },
{ "date": "2026-05-03", "commits": 3 },
{ "date": "2026-05-04", "commits": 0 },
{ "date": "2026-05-05", "commits": 3 },
{ "date": "2026-05-06", "commits": 5 },
{ "date": "2026-05-07", "commits": 8 },
{ "date": "2026-05-08", "commits": 7 },
{ "date": "2026-05-09", "commits": 10 },
{ "date": "2026-05-10", "commits": 12 },
{ "date": "2026-05-11", "commits": 0 },
{ "date": "2026-05-12", "commits": 0 },
{ "date": "2026-05-13", "commits": 13 },
{ "date": "2026-05-14", "commits": 13 },
{ "date": "2026-05-15", "commits": 12 },
{ "date": "2026-05-16", "commits": 7 },
{ "date": "2026-05-17", "commits": 6 },
{ "date": "2026-05-18", "commits": 0 },
{ "date": "2026-05-19", "commits": 0 },
{ "date": "2026-05-20", "commits": 1 },
{ "date": "2026-05-21", "commits": 1 },
{ "date": "2026-05-22", "commits": 2 },
{ "date": "2026-05-23", "commits": 3 },
{ "date": "2026-05-24", "commits": 0 },
{ "date": "2026-05-25", "commits": 0 },
{ "date": "2026-05-26", "commits": 0 },
{ "date": "2026-05-27", "commits": 3 },
{ "date": "2026-05-28", "commits": 0 },
{ "date": "2026-05-29", "commits": 1 },
{ "date": "2026-05-30", "commits": 2 },
{ "date": "2026-05-31", "commits": 3 },
{ "date": "2026-06-01", "commits": 0 },
{ "date": "2026-06-02", "commits": 0 },
{ "date": "2026-06-03", "commits": 2 },
{ "date": "2026-06-04", "commits": 3 },
{ "date": "2026-06-05", "commits": 0 },
{ "date": "2026-06-06", "commits": 1 },
{ "date": "2026-06-07", "commits": 2 },
{ "date": "2026-06-08", "commits": 0 },
{ "date": "2026-06-09", "commits": 0 },
{ "date": "2026-06-10", "commits": 1 },
{ "date": "2026-06-11", "commits": 2 },
{ "date": "2026-06-12", "commits": 3 },
{ "date": "2026-06-13", "commits": 0 },
{ "date": "2026-06-14", "commits": 1 },
{ "date": "2026-06-15", "commits": 0 },
{ "date": "2026-06-16", "commits": 0 },
{ "date": "2026-06-17", "commits": 0 },
{ "date": "2026-06-18", "commits": 1 },
{ "date": "2026-06-19", "commits": 2 },
{ "date": "2026-06-20", "commits": 3 },
{ "date": "2026-06-21", "commits": 0 },
{ "date": "2026-06-22", "commits": 0 },
{ "date": "2026-06-23", "commits": 0 },
{ "date": "2026-06-24", "commits": 3 },
{ "date": "2026-06-25", "commits": 0 },
{ "date": "2026-06-26", "commits": 1 },
{ "date": "2026-06-27", "commits": 2 },
{ "date": "2026-06-28", "commits": 3 },
{ "date": "2026-06-29", "commits": 3 },
{ "date": "2026-06-30", "commits": 0 },
{ "date": "2026-07-01", "commits": 4 },
{ "date": "2026-07-02", "commits": 6 },
{ "date": "2026-07-03", "commits": 6 },
{ "date": "2026-07-04", "commits": 9 },
{ "date": "2026-07-05", "commits": 12 },
{ "date": "2026-07-06", "commits": 0 },
{ "date": "2026-07-07", "commits": 0 },
{ "date": "2026-07-08", "commits": 14 },
{ "date": "2026-07-09", "commits": 15 },
{ "date": "2026-07-10", "commits": 15 },
{ "date": "2026-07-11", "commits": 10 },
{ "date": "2026-07-12", "commits": 9 },
{ "date": "2026-07-13", "commits": 0 },
{ "date": "2026-07-14", "commits": 0 },
{ "date": "2026-07-15", "commits": 2 },
{ "date": "2026-07-16", "commits": 2 },
{ "date": "2026-07-17", "commits": 2 },
{ "date": "2026-07-18", "commits": 3 },
{ "date": "2026-07-19", "commits": 0 },
{ "date": "2026-07-20", "commits": 0 },
{ "date": "2026-07-21", "commits": 3 },
{ "date": "2026-07-22", "commits": 3 },
{ "date": "2026-07-23", "commits": 0 },
{ "date": "2026-07-24", "commits": 1 },
{ "date": "2026-07-25", "commits": 2 },
{ "date": "2026-07-26", "commits": 3 },
{ "date": "2026-07-27", "commits": 0 },
{ "date": "2026-07-28", "commits": 0 },
{ "date": "2026-07-29", "commits": 2 },
{ "date": "2026-07-30", "commits": 3 },
{ "date": "2026-07-31", "commits": 0 },
{ "date": "2026-08-01", "commits": 1 },
{ "date": "2026-08-02", "commits": 2 },
{ "date": "2026-08-03", "commits": 0 },
{ "date": "2026-08-04", "commits": 0 },
{ "date": "2026-08-05", "commits": 1 },
{ "date": "2026-08-06", "commits": 2 },
{ "date": "2026-08-07", "commits": 3 },
{ "date": "2026-08-08", "commits": 0 },
{ "date": "2026-08-09", "commits": 1 },
{ "date": "2026-08-10", "commits": 0 },
{ "date": "2026-08-11", "commits": 0 },
{ "date": "2026-08-12", "commits": 0 },
{ "date": "2026-08-13", "commits": 1 },
{ "date": "2026-08-14", "commits": 2 },
{ "date": "2026-08-15", "commits": 3 },
{ "date": "2026-08-16", "commits": 0 },
{ "date": "2026-08-17", "commits": 0 },
{ "date": "2026-08-18", "commits": 0 },
{ "date": "2026-08-19", "commits": 3 },
{ "date": "2026-08-20", "commits": 0 },
{ "date": "2026-08-21", "commits": 1 },
{ "date": "2026-08-22", "commits": 2 },
{ "date": "2026-08-23", "commits": 3 },
{ "date": "2026-08-24", "commits": 0 },
{ "date": "2026-08-25", "commits": 0 },
{ "date": "2026-08-26", "commits": 3 },
{ "date": "2026-08-27", "commits": 5 },
{ "date": "2026-08-28", "commits": 4 },
{ "date": "2026-08-29", "commits": 7 },
{ "date": "2026-08-30", "commits": 11 },
{ "date": "2026-08-31", "commits": 0 },
{ "date": "2026-09-01", "commits": 0 },
{ "date": "2026-09-02", "commits": 15 },
{ "date": "2026-09-03", "commits": 16 },
{ "date": "2026-09-04", "commits": 16 },
{ "date": "2026-09-05", "commits": 12 },
{ "date": "2026-09-06", "commits": 11 },
{ "date": "2026-09-07", "commits": 0 },
{ "date": "2026-09-08", "commits": 0 },
{ "date": "2026-09-09", "commits": 3 },
{ "date": "2026-09-10", "commits": 3 },
{ "date": "2026-09-11", "commits": 2 },
{ "date": "2026-09-12", "commits": 3 },
{ "date": "2026-09-13", "commits": 0 },
{ "date": "2026-09-14", "commits": 3 },
{ "date": "2026-09-15", "commits": 0 },
{ "date": "2026-09-16", "commits": 3 },
{ "date": "2026-09-17", "commits": 0 },
{ "date": "2026-09-18", "commits": 1 },
{ "date": "2026-09-19", "commits": 2 },
{ "date": "2026-09-20", "commits": 3 },
{ "date": "2026-09-21", "commits": 0 },
{ "date": "2026-09-22", "commits": 0 },
{ "date": "2026-09-23", "commits": 2 },
{ "date": "2026-09-24", "commits": 3 },
{ "date": "2026-09-25", "commits": 0 },
{ "date": "2026-09-26", "commits": 1 },
{ "date": "2026-09-27", "commits": 2 },
{ "date": "2026-09-28", "commits": 0 },
{ "date": "2026-09-29", "commits": 0 },
{ "date": "2026-09-30", "commits": 1 },
{ "date": "2026-10-01", "commits": 2 },
{ "date": "2026-10-02", "commits": 3 },
{ "date": "2026-10-03", "commits": 0 },
{ "date": "2026-10-04", "commits": 1 },
{ "date": "2026-10-05", "commits": 0 },
{ "date": "2026-10-06", "commits": 3 },
{ "date": "2026-10-07", "commits": 0 },
];
export function Example() {
return (
);
}
```
### Data
```tsx
const dailySteps = [
{ date: '2024-01-01', steps: 4210 },
{ date: '2024-01-02', steps: 6890 },
// …one row per day
];
```
One row per UTC day, over at most ten years. January sits at the top and each year is one turn further out, so seasons align. Each day is a bar standing out from the coil; its length and color carry the value. Null days keep a short stub. Duplicate days are rejected.
### Hover
Hover or focus a day to read it in the headline. Click or press Enter to pin; Escape releases. Arrow keys step day by day along the coil. Bars appear in order on load; reduced motion skips it.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `data` (`Row[]`): One row per observation. Omit when using ranges.
- `height` (`number`): Minimum plot height, default 380px. Dense data may expand within the scrollable viewport.
- `depth` (`boolean`): Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
- `color` (`string`): Override the palette with one CSS color.
- `aggregate` (`'sum' | 'mean' | 'max'`): Resting headline summary; Strip defaults to mean, the others to sum.
- `headline` (`number`): Override the resting headline.
- `delta` (`number`): Fractional change shown alongside the headline.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label.
- `ranges` (`{ id, label, data, headline?, delta? }[]`): Period choices with their own data.
- `defaultRange` (`string`): Initial period id.
- `locale` (`string`): Locale for numbers and dates; defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value formatter.
- `badge` (`ReactNode`): Content for the glass tab above the card.
- `className` (`string`): Class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped chart variables.
- `onSelectionChange` (`(selection | null) => void`): Reports id, original row (or null for an absent day), value, and pinned state.
- `renderReadout` (`(selection | null) => ReactNode`): Consumer-owned readout, including when the header is hidden.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `date` (`date, string, or numeric key of Row`): UTC date per day; numbers are milliseconds since the Unix epoch.
- `value` (`numeric key of Row`): Bar length, color, and headline.
- `from` (`string | number | Date`): Inclusive UTC bounds. Defaults to the first and last observed dates.
- `to` (`string | number | Date`): Inclusive UTC bounds. Defaults to the first and last observed dates.
- `domain` (`[number, number]`): Fixed value domain that must contain every value. Defaults to zero through the largest.
- `onKeyDown` (`KeyboardEventHandler`): Keyboard handler on the card frame. Chart inspection also has its own keyboard handling.
## Candlestick chart: `CandlestickChartCard`
The range and direction of every period at a glance, with trading volume underneath. Docs: https://liltui.vercel.app/finance/candlestick
```tsx
import { CandlestickChartCard } from '@lilt-ui/charts/finance';
```
### Complete examples
#### Market card
```tsx
'use client';
import { CandlestickChartCard } from '@lilt-ui/charts/finance';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "1m", "label": "1M", "data": [
{ "date": new Date('2026-08-27T00:00:00.000Z'), "open": 190.78, "high": 196.36, "low": 190.07, "close": 193.85, "volume": 2686171 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "open": 193.85, "high": 197.11, "low": 192.05, "close": 194.2, "volume": 2566984 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "open": 194.2, "high": 194.38, "low": 191.92, "close": 192.45, "volume": 2585676 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "open": 192.45, "high": 192.6, "low": 190.83, "close": 191.48, "volume": 2902453 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "open": 191.48, "high": 195.18, "low": 190.07, "close": 194.15, "volume": 2226035 },
{ "date": new Date('2026-09-01T00:00:00.000Z'), "open": 194.15, "high": 194.96, "low": 191.2, "close": 194.68, "volume": 2865378 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "open": 194.68, "high": 195.97, "low": 191.95, "close": 192.18, "volume": 3179562 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "open": 192.18, "high": 197.54, "low": 190.1, "close": 195.29, "volume": 2203328 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "open": 195.29, "high": 200.11, "low": 193.34, "close": 197.72, "volume": 3287887 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "open": 197.72, "high": 202.47, "low": 196.55, "close": 200.86, "volume": 2108982 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "open": 200.86, "high": 202.44, "low": 200.14, "close": 201.7, "volume": 3050788 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "open": 201.7, "high": 206.09, "low": 201.08, "close": 203.76, "volume": 3160303 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "open": 203.76, "high": 205.09, "low": 203.28, "close": 203.62, "volume": 1547552 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "open": 203.62, "high": 206.45, "low": 199.93, "close": 200.54, "volume": 2419421 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "open": 200.54, "high": 203.41, "low": 196.4, "close": 199.31, "volume": 2137922 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "open": 199.31, "high": 201.44, "low": 197.01, "close": 197.94, "volume": 2856143 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "open": 197.94, "high": 200.87, "low": 193.01, "close": 195.54, "volume": 2016849 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "open": 195.54, "high": 197.51, "low": 192.95, "close": 196.79, "volume": 2621817 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "open": 196.79, "high": 199.2, "low": 194.82, "close": 197.52, "volume": 3033046 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "open": 197.52, "high": 203.69, "low": 197, "close": 200.66, "volume": 3041051 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "open": 200.66, "high": 204.11, "low": 198.61, "close": 203.59, "volume": 2082501 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "open": 203.59, "high": 208.28, "low": 201.87, "close": 205.27, "volume": 3222974 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "open": 205.27, "high": 206.64, "low": 203, "close": 203.49, "volume": 2462821 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "open": 203.49, "high": 204.33, "low": 198.71, "close": 200.51, "volume": 2368043 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "open": 200.51, "high": 204.21, "low": 199.53, "close": 204.04, "volume": 2964809 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "open": 204.04, "high": 205.6, "low": 199.82, "close": 201.65, "volume": 3263425 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "open": 201.65, "high": 206.26, "low": 198.81, "close": 203.2, "volume": 3180001 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "open": 203.2, "high": 206.48, "low": 200.12, "close": 205.46, "volume": 2041039 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "open": 205.46, "high": 208.24, "low": 202.34, "close": 203.24, "volume": 2468141 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "open": 203.24, "high": 206, "low": 202.82, "close": 205.56, "volume": 2886985 },
] },
{ "id": "3m", "label": "3M", "data": [
{ "date": new Date('2026-06-28T00:00:00.000Z'), "open": 175.33, "high": 180.25, "low": 174.18, "close": 178.33, "volume": 3702584 },
{ "date": new Date('2026-06-29T00:00:00.000Z'), "open": 178.33, "high": 178.83, "low": 175.83, "close": 176.69, "volume": 2561676 },
{ "date": new Date('2026-06-30T00:00:00.000Z'), "open": 176.69, "high": 178.45, "low": 175.77, "close": 176.71, "volume": 1691710 },
{ "date": new Date('2026-07-01T00:00:00.000Z'), "open": 176.71, "high": 177.68, "low": 174.58, "close": 175.69, "volume": 1891064 },
{ "date": new Date('2026-07-02T00:00:00.000Z'), "open": 175.69, "high": 176.87, "low": 172.86, "close": 175.31, "volume": 1862025 },
{ "date": new Date('2026-07-03T00:00:00.000Z'), "open": 175.31, "high": 178.66, "low": 173.7, "close": 178.41, "volume": 2873801 },
{ "date": new Date('2026-07-04T00:00:00.000Z'), "open": 178.41, "high": 181.32, "low": 176.93, "close": 179.67, "volume": 2917261 },
{ "date": new Date('2026-07-05T00:00:00.000Z'), "open": 179.67, "high": 182.32, "low": 176.74, "close": 178.41, "volume": 1924836 },
{ "date": new Date('2026-07-06T00:00:00.000Z'), "open": 178.41, "high": 182.22, "low": 175.89, "close": 181.04, "volume": 2601632 },
{ "date": new Date('2026-07-07T00:00:00.000Z'), "open": 181.04, "high": 181.73, "low": 177.68, "close": 178.74, "volume": 2747583 },
{ "date": new Date('2026-07-08T00:00:00.000Z'), "open": 178.74, "high": 180.38, "low": 176.15, "close": 180.24, "volume": 1829364 },
{ "date": new Date('2026-07-09T00:00:00.000Z'), "open": 180.24, "high": 181.75, "low": 176.53, "close": 178.88, "volume": 2875169 },
{ "date": new Date('2026-07-10T00:00:00.000Z'), "open": 178.88, "high": 180.17, "low": 178.39, "close": 180.16, "volume": 1771891 },
{ "date": new Date('2026-07-11T00:00:00.000Z'), "open": 180.16, "high": 182.25, "low": 178.11, "close": 178.34, "volume": 1760700 },
{ "date": new Date('2026-07-12T00:00:00.000Z'), "open": 178.34, "high": 183.67, "low": 175.68, "close": 181.53, "volume": 2986133 },
{ "date": new Date('2026-07-13T00:00:00.000Z'), "open": 181.53, "high": 183.06, "low": 178.25, "close": 180.7, "volume": 2754332 },
{ "date": new Date('2026-07-14T00:00:00.000Z'), "open": 180.7, "high": 182.04, "low": 178.8, "close": 181.02, "volume": 2853710 },
{ "date": new Date('2026-07-15T00:00:00.000Z'), "open": 181.02, "high": 184.6, "low": 178.5, "close": 182.81, "volume": 3309967 },
{ "date": new Date('2026-07-16T00:00:00.000Z'), "open": 182.81, "high": 187.85, "low": 180.39, "close": 185.86, "volume": 2219317 },
{ "date": new Date('2026-07-17T00:00:00.000Z'), "open": 185.86, "high": 186.1, "low": 181.67, "close": 184.07, "volume": 2014204 },
{ "date": new Date('2026-07-18T00:00:00.000Z'), "open": 184.07, "high": 185.04, "low": 180.87, "close": 182.15, "volume": 2597964 },
{ "date": new Date('2026-07-19T00:00:00.000Z'), "open": 182.15, "high": 185.62, "low": 181.28, "close": 182.95, "volume": 1855149 },
{ "date": new Date('2026-07-20T00:00:00.000Z'), "open": 182.95, "high": 184.31, "low": 179.38, "close": 180.08, "volume": 3538359 },
{ "date": new Date('2026-07-21T00:00:00.000Z'), "open": 180.08, "high": 183.87, "low": 178.35, "close": 182.21, "volume": 2111130 },
{ "date": new Date('2026-07-22T00:00:00.000Z'), "open": 182.21, "high": 183.77, "low": 179.79, "close": 182.59, "volume": 2470964 },
{ "date": new Date('2026-07-23T00:00:00.000Z'), "open": 182.59, "high": 185.11, "low": 178.74, "close": 180, "volume": 2215306 },
{ "date": new Date('2026-07-24T00:00:00.000Z'), "open": 180, "high": 182.37, "low": 179.22, "close": 181.3, "volume": 1930100 },
{ "date": new Date('2026-07-25T00:00:00.000Z'), "open": 181.3, "high": 182.29, "low": 176.78, "close": 179.41, "volume": 2564712 },
{ "date": new Date('2026-07-26T00:00:00.000Z'), "open": 179.41, "high": 181.57, "low": 176.8, "close": 179.78, "volume": 2695389 },
{ "date": new Date('2026-07-27T00:00:00.000Z'), "open": 179.78, "high": 183.37, "low": 177.65, "close": 182.53, "volume": 2612169 },
{ "date": new Date('2026-07-28T00:00:00.000Z'), "open": 182.53, "high": 185.98, "low": 180.64, "close": 185.06, "volume": 2871046 },
{ "date": new Date('2026-07-29T00:00:00.000Z'), "open": 185.06, "high": 185.86, "low": 180.35, "close": 182.69, "volume": 1950375 },
{ "date": new Date('2026-07-30T00:00:00.000Z'), "open": 182.69, "high": 185.15, "low": 177.55, "close": 180.14, "volume": 3537483 },
{ "date": new Date('2026-07-31T00:00:00.000Z'), "open": 180.14, "high": 180.56, "low": 178.7, "close": 179.29, "volume": 3027806 },
{ "date": new Date('2026-08-01T00:00:00.000Z'), "open": 179.29, "high": 183.63, "low": 178.43, "close": 181.63, "volume": 2848629 },
{ "date": new Date('2026-08-02T00:00:00.000Z'), "open": 181.63, "high": 185.46, "low": 179.23, "close": 182.99, "volume": 2719123 },
{ "date": new Date('2026-08-03T00:00:00.000Z'), "open": 182.99, "high": 183.03, "low": 181.76, "close": 181.94, "volume": 2892428 },
{ "date": new Date('2026-08-04T00:00:00.000Z'), "open": 181.94, "high": 184.62, "low": 181.8, "close": 182.87, "volume": 3059787 },
{ "date": new Date('2026-08-05T00:00:00.000Z'), "open": 182.87, "high": 183.86, "low": 179.61, "close": 180.65, "volume": 3153744 },
{ "date": new Date('2026-08-06T00:00:00.000Z'), "open": 180.65, "high": 183.48, "low": 180.36, "close": 183.38, "volume": 2096144 },
{ "date": new Date('2026-08-07T00:00:00.000Z'), "open": 183.38, "high": 183.72, "low": 179.24, "close": 181.35, "volume": 2428129 },
{ "date": new Date('2026-08-08T00:00:00.000Z'), "open": 181.35, "high": 183.15, "low": 178.87, "close": 181.68, "volume": 1957201 },
{ "date": new Date('2026-08-09T00:00:00.000Z'), "open": 181.68, "high": 184.48, "low": 180.15, "close": 184.09, "volume": 3131278 },
{ "date": new Date('2026-08-10T00:00:00.000Z'), "open": 184.09, "high": 187.25, "low": 182.16, "close": 184.76, "volume": 1986018 },
{ "date": new Date('2026-08-11T00:00:00.000Z'), "open": 184.76, "high": 185.27, "low": 181.34, "close": 184.06, "volume": 2629438 },
{ "date": new Date('2026-08-12T00:00:00.000Z'), "open": 184.06, "high": 185.48, "low": 181.89, "close": 182.38, "volume": 2086285 },
{ "date": new Date('2026-08-13T00:00:00.000Z'), "open": 182.38, "high": 185.11, "low": 180.61, "close": 183.66, "volume": 2860446 },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "open": 183.66, "high": 184.63, "low": 180.29, "close": 181.67, "volume": 2398495 },
{ "date": new Date('2026-08-15T00:00:00.000Z'), "open": 181.67, "high": 185.05, "low": 179.28, "close": 184.46, "volume": 2448935 },
{ "date": new Date('2026-08-16T00:00:00.000Z'), "open": 184.46, "high": 187.8, "low": 182.88, "close": 186.13, "volume": 2425201 },
{ "date": new Date('2026-08-17T00:00:00.000Z'), "open": 186.13, "high": 188.94, "low": 184.01, "close": 184.01, "volume": 2897024 },
{ "date": new Date('2026-08-18T00:00:00.000Z'), "open": 184.01, "high": 185.14, "low": 181.96, "close": 185.05, "volume": 2346585 },
{ "date": new Date('2026-08-19T00:00:00.000Z'), "open": 185.05, "high": 187.56, "low": 181.6, "close": 183.2, "volume": 1782162 },
{ "date": new Date('2026-08-20T00:00:00.000Z'), "open": 183.2, "high": 183.37, "low": 181.1, "close": 182.24, "volume": 3222334 },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "open": 182.24, "high": 187.12, "low": 180.33, "close": 184.51, "volume": 2058942 },
{ "date": new Date('2026-08-22T00:00:00.000Z'), "open": 184.51, "high": 187.36, "low": 184.49, "close": 186.44, "volume": 1849602 },
{ "date": new Date('2026-08-23T00:00:00.000Z'), "open": 186.44, "high": 189.61, "low": 183.73, "close": 188.9, "volume": 1968815 },
{ "date": new Date('2026-08-24T00:00:00.000Z'), "open": 188.9, "high": 192.67, "low": 188.31, "close": 191.85, "volume": 3047593 },
{ "date": new Date('2026-08-25T00:00:00.000Z'), "open": 191.85, "high": 194.69, "low": 188.25, "close": 190.53, "volume": 1890866 },
{ "date": new Date('2026-08-26T00:00:00.000Z'), "open": 190.53, "high": 192.03, "low": 188.23, "close": 190.78, "volume": 1826419 },
{ "date": new Date('2026-08-27T00:00:00.000Z'), "open": 190.78, "high": 196.36, "low": 190.07, "close": 193.85, "volume": 2686171 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "open": 193.85, "high": 197.11, "low": 192.05, "close": 194.2, "volume": 2566984 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "open": 194.2, "high": 194.38, "low": 191.92, "close": 192.45, "volume": 2585676 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "open": 192.45, "high": 192.6, "low": 190.83, "close": 191.48, "volume": 2902453 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "open": 191.48, "high": 195.18, "low": 190.07, "close": 194.15, "volume": 2226035 },
{ "date": new Date('2026-09-01T00:00:00.000Z'), "open": 194.15, "high": 194.96, "low": 191.2, "close": 194.68, "volume": 2865378 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "open": 194.68, "high": 195.97, "low": 191.95, "close": 192.18, "volume": 3179562 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "open": 192.18, "high": 197.54, "low": 190.1, "close": 195.29, "volume": 2203328 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "open": 195.29, "high": 200.11, "low": 193.34, "close": 197.72, "volume": 3287887 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "open": 197.72, "high": 202.47, "low": 196.55, "close": 200.86, "volume": 2108982 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "open": 200.86, "high": 202.44, "low": 200.14, "close": 201.7, "volume": 3050788 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "open": 201.7, "high": 206.09, "low": 201.08, "close": 203.76, "volume": 3160303 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "open": 203.76, "high": 205.09, "low": 203.28, "close": 203.62, "volume": 1547552 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "open": 203.62, "high": 206.45, "low": 199.93, "close": 200.54, "volume": 2419421 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "open": 200.54, "high": 203.41, "low": 196.4, "close": 199.31, "volume": 2137922 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "open": 199.31, "high": 201.44, "low": 197.01, "close": 197.94, "volume": 2856143 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "open": 197.94, "high": 200.87, "low": 193.01, "close": 195.54, "volume": 2016849 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "open": 195.54, "high": 197.51, "low": 192.95, "close": 196.79, "volume": 2621817 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "open": 196.79, "high": 199.2, "low": 194.82, "close": 197.52, "volume": 3033046 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "open": 197.52, "high": 203.69, "low": 197, "close": 200.66, "volume": 3041051 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "open": 200.66, "high": 204.11, "low": 198.61, "close": 203.59, "volume": 2082501 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "open": 203.59, "high": 208.28, "low": 201.87, "close": 205.27, "volume": 3222974 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "open": 205.27, "high": 206.64, "low": 203, "close": 203.49, "volume": 2462821 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "open": 203.49, "high": 204.33, "low": 198.71, "close": 200.51, "volume": 2368043 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "open": 200.51, "high": 204.21, "low": 199.53, "close": 204.04, "volume": 2964809 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "open": 204.04, "high": 205.6, "low": 199.82, "close": 201.65, "volume": 3263425 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "open": 201.65, "high": 206.26, "low": 198.81, "close": 203.2, "volume": 3180001 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "open": 203.2, "high": 206.48, "low": 200.12, "close": 205.46, "volume": 2041039 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "open": 205.46, "high": 208.24, "low": 202.34, "close": 203.24, "volume": 2468141 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "open": 203.24, "high": 206, "low": 202.82, "close": 205.56, "volume": 2886985 },
] },
{ "id": "6m", "label": "6M", "data": [
{ "date": new Date('2026-03-28T00:00:00.000Z'), "open": 145.73, "high": 148.07, "low": 145.41, "close": 147.17, "volume": 2899898 },
{ "date": new Date('2026-03-29T00:00:00.000Z'), "open": 147.17, "high": 151.54, "low": 146.53, "close": 149.83, "volume": 2585536 },
{ "date": new Date('2026-03-30T00:00:00.000Z'), "open": 149.83, "high": 150.65, "low": 146.57, "close": 148.2, "volume": 1801152 },
{ "date": new Date('2026-03-31T00:00:00.000Z'), "open": 148.2, "high": 148.77, "low": 146.89, "close": 148.5, "volume": 2870322 },
{ "date": new Date('2026-04-01T00:00:00.000Z'), "open": 148.5, "high": 153.27, "low": 147.82, "close": 151.01, "volume": 3444678 },
{ "date": new Date('2026-04-02T00:00:00.000Z'), "open": 151.01, "high": 152.29, "low": 148.98, "close": 151.21, "volume": 1561281 },
{ "date": new Date('2026-04-03T00:00:00.000Z'), "open": 151.21, "high": 154.03, "low": 149.25, "close": 152.63, "volume": 2220081 },
{ "date": new Date('2026-04-04T00:00:00.000Z'), "open": 152.63, "high": 152.79, "low": 149.52, "close": 151.13, "volume": 2781695 },
{ "date": new Date('2026-04-05T00:00:00.000Z'), "open": 151.13, "high": 154.6, "low": 150.87, "close": 153.81, "volume": 2867194 },
{ "date": new Date('2026-04-06T00:00:00.000Z'), "open": 153.81, "high": 157.44, "low": 152.33, "close": 156.09, "volume": 3444996 },
{ "date": new Date('2026-04-07T00:00:00.000Z'), "open": 156.09, "high": 156.68, "low": 154.82, "close": 156.57, "volume": 1744423 },
{ "date": new Date('2026-04-08T00:00:00.000Z'), "open": 156.57, "high": 157.78, "low": 153.72, "close": 155.24, "volume": 2450699 },
{ "date": new Date('2026-04-09T00:00:00.000Z'), "open": 155.24, "high": 155.25, "low": 152.91, "close": 153.65, "volume": 1987237 },
{ "date": new Date('2026-04-10T00:00:00.000Z'), "open": 153.65, "high": 156.22, "low": 152.27, "close": 154.39, "volume": 1666324 },
{ "date": new Date('2026-04-11T00:00:00.000Z'), "open": 154.39, "high": 155.51, "low": 153.82, "close": 155.36, "volume": 2021039 },
{ "date": new Date('2026-04-12T00:00:00.000Z'), "open": 155.36, "high": 155.75, "low": 155.11, "close": 155.29, "volume": 2937036 },
{ "date": new Date('2026-04-13T00:00:00.000Z'), "open": 155.29, "high": 155.56, "low": 151.57, "close": 153.7, "volume": 1996865 },
{ "date": new Date('2026-04-14T00:00:00.000Z'), "open": 153.7, "high": 156.04, "low": 151.32, "close": 151.8, "volume": 2238815 },
{ "date": new Date('2026-04-15T00:00:00.000Z'), "open": 151.8, "high": 155.39, "low": 150.25, "close": 153.74, "volume": 3217911 },
{ "date": new Date('2026-04-16T00:00:00.000Z'), "open": 153.74, "high": 157.57, "low": 151.84, "close": 155.24, "volume": 2119930 },
{ "date": new Date('2026-04-17T00:00:00.000Z'), "open": 155.24, "high": 156.06, "low": 152.91, "close": 154.93, "volume": 1760989 },
{ "date": new Date('2026-04-18T00:00:00.000Z'), "open": 154.93, "high": 156.61, "low": 151.45, "close": 152.56, "volume": 2411306 },
{ "date": new Date('2026-04-19T00:00:00.000Z'), "open": 152.56, "high": 153.69, "low": 148.84, "close": 150.35, "volume": 2106919 },
{ "date": new Date('2026-04-20T00:00:00.000Z'), "open": 150.35, "high": 153.5, "low": 150.2, "close": 152.49, "volume": 2449872 },
{ "date": new Date('2026-04-21T00:00:00.000Z'), "open": 152.49, "high": 154.63, "low": 150.52, "close": 150.85, "volume": 2773442 },
{ "date": new Date('2026-04-22T00:00:00.000Z'), "open": 150.85, "high": 152.73, "low": 148.78, "close": 150.74, "volume": 1461180 },
{ "date": new Date('2026-04-23T00:00:00.000Z'), "open": 150.74, "high": 153.37, "low": 149.77, "close": 153.34, "volume": 3687707 },
{ "date": new Date('2026-04-24T00:00:00.000Z'), "open": 153.34, "high": 153.34, "low": 150.12, "close": 152.09, "volume": 2527334 },
{ "date": new Date('2026-04-25T00:00:00.000Z'), "open": 152.09, "high": 153.71, "low": 150.52, "close": 152.37, "volume": 1983212 },
{ "date": new Date('2026-04-26T00:00:00.000Z'), "open": 152.37, "high": 154.61, "low": 150.07, "close": 152.73, "volume": 2228479 },
{ "date": new Date('2026-04-27T00:00:00.000Z'), "open": 152.73, "high": 156.76, "low": 152.42, "close": 154.44, "volume": 2173658 },
{ "date": new Date('2026-04-28T00:00:00.000Z'), "open": 154.44, "high": 155.74, "low": 152.48, "close": 155.66, "volume": 2669832 },
{ "date": new Date('2026-04-29T00:00:00.000Z'), "open": 155.66, "high": 158.19, "low": 154.64, "close": 156.77, "volume": 3039806 },
{ "date": new Date('2026-04-30T00:00:00.000Z'), "open": 156.77, "high": 160.39, "low": 154.5, "close": 159.22, "volume": 2032129 },
{ "date": new Date('2026-05-01T00:00:00.000Z'), "open": 159.22, "high": 159.61, "low": 156.08, "close": 157.01, "volume": 3142221 },
{ "date": new Date('2026-05-02T00:00:00.000Z'), "open": 157.01, "high": 157.59, "low": 154.3, "close": 155.92, "volume": 2751851 },
{ "date": new Date('2026-05-03T00:00:00.000Z'), "open": 155.92, "high": 159.53, "low": 153.9, "close": 158.46, "volume": 2063295 },
{ "date": new Date('2026-05-04T00:00:00.000Z'), "open": 158.46, "high": 161.28, "low": 157.89, "close": 160.86, "volume": 3193688 },
{ "date": new Date('2026-05-05T00:00:00.000Z'), "open": 160.86, "high": 163.29, "low": 158.21, "close": 160.34, "volume": 2776757 },
{ "date": new Date('2026-05-06T00:00:00.000Z'), "open": 160.34, "high": 162.91, "low": 158.24, "close": 160.84, "volume": 1530875 },
{ "date": new Date('2026-05-07T00:00:00.000Z'), "open": 160.84, "high": 165.76, "low": 159.81, "close": 163.66, "volume": 3272444 },
{ "date": new Date('2026-05-08T00:00:00.000Z'), "open": 163.66, "high": 167.1, "low": 162.88, "close": 165, "volume": 2914948 },
{ "date": new Date('2026-05-09T00:00:00.000Z'), "open": 165, "high": 166.61, "low": 163.64, "close": 164.19, "volume": 2912552 },
{ "date": new Date('2026-05-10T00:00:00.000Z'), "open": 164.19, "high": 166.67, "low": 162.65, "close": 162.88, "volume": 1857223 },
{ "date": new Date('2026-05-11T00:00:00.000Z'), "open": 162.88, "high": 163.4, "low": 161.22, "close": 163.06, "volume": 2688559 },
{ "date": new Date('2026-05-12T00:00:00.000Z'), "open": 163.06, "high": 167.26, "low": 161.86, "close": 164.94, "volume": 3262744 },
{ "date": new Date('2026-05-13T00:00:00.000Z'), "open": 164.94, "high": 169.28, "low": 163.15, "close": 167.47, "volume": 2715268 },
{ "date": new Date('2026-05-14T00:00:00.000Z'), "open": 167.47, "high": 169.14, "low": 166.23, "close": 167.62, "volume": 2496159 },
{ "date": new Date('2026-05-15T00:00:00.000Z'), "open": 167.62, "high": 169.78, "low": 166.89, "close": 169.28, "volume": 2835271 },
{ "date": new Date('2026-05-16T00:00:00.000Z'), "open": 169.28, "high": 170.41, "low": 166.83, "close": 168.98, "volume": 1851239 },
{ "date": new Date('2026-05-17T00:00:00.000Z'), "open": 168.98, "high": 172.53, "low": 167.83, "close": 170.99, "volume": 2175470 },
{ "date": new Date('2026-05-18T00:00:00.000Z'), "open": 170.99, "high": 173.45, "low": 168.74, "close": 169.09, "volume": 2317336 },
{ "date": new Date('2026-05-19T00:00:00.000Z'), "open": 169.09, "high": 172.51, "low": 166.85, "close": 170.96, "volume": 2279714 },
{ "date": new Date('2026-05-20T00:00:00.000Z'), "open": 170.96, "high": 173.64, "low": 169.41, "close": 171.33, "volume": 2598995 },
{ "date": new Date('2026-05-21T00:00:00.000Z'), "open": 171.33, "high": 173.01, "low": 169.05, "close": 170, "volume": 1941274 },
{ "date": new Date('2026-05-22T00:00:00.000Z'), "open": 170, "high": 170.87, "low": 167.4, "close": 170.01, "volume": 2223511 },
{ "date": new Date('2026-05-23T00:00:00.000Z'), "open": 170.01, "high": 170.91, "low": 166.5, "close": 168.73, "volume": 2776761 },
{ "date": new Date('2026-05-24T00:00:00.000Z'), "open": 168.73, "high": 169.99, "low": 166.96, "close": 167.73, "volume": 3029364 },
{ "date": new Date('2026-05-25T00:00:00.000Z'), "open": 167.73, "high": 171.03, "low": 166.9, "close": 169.8, "volume": 2426138 },
{ "date": new Date('2026-05-26T00:00:00.000Z'), "open": 169.8, "high": 170.23, "low": 168.44, "close": 169.91, "volume": 1479940 },
{ "date": new Date('2026-05-27T00:00:00.000Z'), "open": 169.91, "high": 171.32, "low": 166.65, "close": 167.8, "volume": 2339555 },
{ "date": new Date('2026-05-28T00:00:00.000Z'), "open": 167.8, "high": 169.88, "low": 165.53, "close": 168.8, "volume": 3143896 },
{ "date": new Date('2026-05-29T00:00:00.000Z'), "open": 168.8, "high": 172.53, "low": 167, "close": 171.42, "volume": 3569036 },
{ "date": new Date('2026-05-30T00:00:00.000Z'), "open": 171.42, "high": 172.42, "low": 171.38, "close": 171.52, "volume": 2395288 },
{ "date": new Date('2026-05-31T00:00:00.000Z'), "open": 171.52, "high": 174.19, "low": 170.56, "close": 171.94, "volume": 1990912 },
{ "date": new Date('2026-06-01T00:00:00.000Z'), "open": 171.94, "high": 173.36, "low": 171.9, "close": 172.14, "volume": 2707900 },
{ "date": new Date('2026-06-02T00:00:00.000Z'), "open": 172.14, "high": 174.94, "low": 171.29, "close": 174.9, "volume": 2731770 },
{ "date": new Date('2026-06-03T00:00:00.000Z'), "open": 174.9, "high": 178.13, "low": 172.81, "close": 176.92, "volume": 3194193 },
{ "date": new Date('2026-06-04T00:00:00.000Z'), "open": 176.92, "high": 178.26, "low": 173.44, "close": 174.62, "volume": 2227849 },
{ "date": new Date('2026-06-05T00:00:00.000Z'), "open": 174.62, "high": 174.99, "low": 171.99, "close": 172.53, "volume": 1952142 },
{ "date": new Date('2026-06-06T00:00:00.000Z'), "open": 172.53, "high": 172.9, "low": 169.67, "close": 172.05, "volume": 1483655 },
{ "date": new Date('2026-06-07T00:00:00.000Z'), "open": 172.05, "high": 173.81, "low": 170.31, "close": 170.99, "volume": 2016829 },
{ "date": new Date('2026-06-08T00:00:00.000Z'), "open": 170.99, "high": 174.14, "low": 169.52, "close": 173.4, "volume": 2847738 },
{ "date": new Date('2026-06-09T00:00:00.000Z'), "open": 173.4, "high": 174.82, "low": 171.09, "close": 172.73, "volume": 3025302 },
{ "date": new Date('2026-06-10T00:00:00.000Z'), "open": 172.73, "high": 175.24, "low": 169.06, "close": 171.38, "volume": 2619529 },
{ "date": new Date('2026-06-11T00:00:00.000Z'), "open": 171.38, "high": 173.96, "low": 168.95, "close": 168.98, "volume": 1944874 },
{ "date": new Date('2026-06-12T00:00:00.000Z'), "open": 168.98, "high": 171.8, "low": 168.17, "close": 171.24, "volume": 3509680 },
{ "date": new Date('2026-06-13T00:00:00.000Z'), "open": 171.24, "high": 174.44, "low": 170.79, "close": 172.07, "volume": 3186503 },
{ "date": new Date('2026-06-14T00:00:00.000Z'), "open": 172.07, "high": 173.69, "low": 167.88, "close": 170.2, "volume": 2170077 },
{ "date": new Date('2026-06-15T00:00:00.000Z'), "open": 170.2, "high": 175.03, "low": 169.27, "close": 172.5, "volume": 2721369 },
{ "date": new Date('2026-06-16T00:00:00.000Z'), "open": 172.5, "high": 176.4, "low": 171.91, "close": 174.49, "volume": 3009601 },
{ "date": new Date('2026-06-17T00:00:00.000Z'), "open": 174.49, "high": 176.68, "low": 173.6, "close": 174.02, "volume": 2714240 },
{ "date": new Date('2026-06-18T00:00:00.000Z'), "open": 174.02, "high": 178.82, "low": 172.25, "close": 176.38, "volume": 2488549 },
{ "date": new Date('2026-06-19T00:00:00.000Z'), "open": 176.38, "high": 179.52, "low": 173.8, "close": 178.3, "volume": 2184126 },
{ "date": new Date('2026-06-20T00:00:00.000Z'), "open": 178.3, "high": 179.44, "low": 177.72, "close": 178.06, "volume": 2206916 },
{ "date": new Date('2026-06-21T00:00:00.000Z'), "open": 178.06, "high": 179.65, "low": 175.56, "close": 176.36, "volume": 2968498 },
{ "date": new Date('2026-06-22T00:00:00.000Z'), "open": 176.36, "high": 178.75, "low": 173.65, "close": 173.66, "volume": 2018748 },
{ "date": new Date('2026-06-23T00:00:00.000Z'), "open": 173.66, "high": 175.77, "low": 173.28, "close": 173.29, "volume": 1493203 },
{ "date": new Date('2026-06-24T00:00:00.000Z'), "open": 173.29, "high": 174.25, "low": 171.2, "close": 174.17, "volume": 1677755 },
{ "date": new Date('2026-06-25T00:00:00.000Z'), "open": 174.17, "high": 176.49, "low": 172.14, "close": 174.18, "volume": 2195255 },
{ "date": new Date('2026-06-26T00:00:00.000Z'), "open": 174.18, "high": 176.23, "low": 170.05, "close": 172.55, "volume": 1956910 },
{ "date": new Date('2026-06-27T00:00:00.000Z'), "open": 172.55, "high": 177.03, "low": 172.1, "close": 175.33, "volume": 2294555 },
{ "date": new Date('2026-06-28T00:00:00.000Z'), "open": 175.33, "high": 180.25, "low": 174.18, "close": 178.33, "volume": 3702584 },
{ "date": new Date('2026-06-29T00:00:00.000Z'), "open": 178.33, "high": 178.83, "low": 175.83, "close": 176.69, "volume": 2561676 },
{ "date": new Date('2026-06-30T00:00:00.000Z'), "open": 176.69, "high": 178.45, "low": 175.77, "close": 176.71, "volume": 1691710 },
{ "date": new Date('2026-07-01T00:00:00.000Z'), "open": 176.71, "high": 177.68, "low": 174.58, "close": 175.69, "volume": 1891064 },
{ "date": new Date('2026-07-02T00:00:00.000Z'), "open": 175.69, "high": 176.87, "low": 172.86, "close": 175.31, "volume": 1862025 },
{ "date": new Date('2026-07-03T00:00:00.000Z'), "open": 175.31, "high": 178.66, "low": 173.7, "close": 178.41, "volume": 2873801 },
{ "date": new Date('2026-07-04T00:00:00.000Z'), "open": 178.41, "high": 181.32, "low": 176.93, "close": 179.67, "volume": 2917261 },
{ "date": new Date('2026-07-05T00:00:00.000Z'), "open": 179.67, "high": 182.32, "low": 176.74, "close": 178.41, "volume": 1924836 },
{ "date": new Date('2026-07-06T00:00:00.000Z'), "open": 178.41, "high": 182.22, "low": 175.89, "close": 181.04, "volume": 2601632 },
{ "date": new Date('2026-07-07T00:00:00.000Z'), "open": 181.04, "high": 181.73, "low": 177.68, "close": 178.74, "volume": 2747583 },
{ "date": new Date('2026-07-08T00:00:00.000Z'), "open": 178.74, "high": 180.38, "low": 176.15, "close": 180.24, "volume": 1829364 },
{ "date": new Date('2026-07-09T00:00:00.000Z'), "open": 180.24, "high": 181.75, "low": 176.53, "close": 178.88, "volume": 2875169 },
{ "date": new Date('2026-07-10T00:00:00.000Z'), "open": 178.88, "high": 180.17, "low": 178.39, "close": 180.16, "volume": 1771891 },
{ "date": new Date('2026-07-11T00:00:00.000Z'), "open": 180.16, "high": 182.25, "low": 178.11, "close": 178.34, "volume": 1760700 },
{ "date": new Date('2026-07-12T00:00:00.000Z'), "open": 178.34, "high": 183.67, "low": 175.68, "close": 181.53, "volume": 2986133 },
{ "date": new Date('2026-07-13T00:00:00.000Z'), "open": 181.53, "high": 183.06, "low": 178.25, "close": 180.7, "volume": 2754332 },
{ "date": new Date('2026-07-14T00:00:00.000Z'), "open": 180.7, "high": 182.04, "low": 178.8, "close": 181.02, "volume": 2853710 },
{ "date": new Date('2026-07-15T00:00:00.000Z'), "open": 181.02, "high": 184.6, "low": 178.5, "close": 182.81, "volume": 3309967 },
{ "date": new Date('2026-07-16T00:00:00.000Z'), "open": 182.81, "high": 187.85, "low": 180.39, "close": 185.86, "volume": 2219317 },
{ "date": new Date('2026-07-17T00:00:00.000Z'), "open": 185.86, "high": 186.1, "low": 181.67, "close": 184.07, "volume": 2014204 },
{ "date": new Date('2026-07-18T00:00:00.000Z'), "open": 184.07, "high": 185.04, "low": 180.87, "close": 182.15, "volume": 2597964 },
{ "date": new Date('2026-07-19T00:00:00.000Z'), "open": 182.15, "high": 185.62, "low": 181.28, "close": 182.95, "volume": 1855149 },
{ "date": new Date('2026-07-20T00:00:00.000Z'), "open": 182.95, "high": 184.31, "low": 179.38, "close": 180.08, "volume": 3538359 },
{ "date": new Date('2026-07-21T00:00:00.000Z'), "open": 180.08, "high": 183.87, "low": 178.35, "close": 182.21, "volume": 2111130 },
{ "date": new Date('2026-07-22T00:00:00.000Z'), "open": 182.21, "high": 183.77, "low": 179.79, "close": 182.59, "volume": 2470964 },
{ "date": new Date('2026-07-23T00:00:00.000Z'), "open": 182.59, "high": 185.11, "low": 178.74, "close": 180, "volume": 2215306 },
{ "date": new Date('2026-07-24T00:00:00.000Z'), "open": 180, "high": 182.37, "low": 179.22, "close": 181.3, "volume": 1930100 },
{ "date": new Date('2026-07-25T00:00:00.000Z'), "open": 181.3, "high": 182.29, "low": 176.78, "close": 179.41, "volume": 2564712 },
{ "date": new Date('2026-07-26T00:00:00.000Z'), "open": 179.41, "high": 181.57, "low": 176.8, "close": 179.78, "volume": 2695389 },
{ "date": new Date('2026-07-27T00:00:00.000Z'), "open": 179.78, "high": 183.37, "low": 177.65, "close": 182.53, "volume": 2612169 },
{ "date": new Date('2026-07-28T00:00:00.000Z'), "open": 182.53, "high": 185.98, "low": 180.64, "close": 185.06, "volume": 2871046 },
{ "date": new Date('2026-07-29T00:00:00.000Z'), "open": 185.06, "high": 185.86, "low": 180.35, "close": 182.69, "volume": 1950375 },
{ "date": new Date('2026-07-30T00:00:00.000Z'), "open": 182.69, "high": 185.15, "low": 177.55, "close": 180.14, "volume": 3537483 },
{ "date": new Date('2026-07-31T00:00:00.000Z'), "open": 180.14, "high": 180.56, "low": 178.7, "close": 179.29, "volume": 3027806 },
{ "date": new Date('2026-08-01T00:00:00.000Z'), "open": 179.29, "high": 183.63, "low": 178.43, "close": 181.63, "volume": 2848629 },
{ "date": new Date('2026-08-02T00:00:00.000Z'), "open": 181.63, "high": 185.46, "low": 179.23, "close": 182.99, "volume": 2719123 },
{ "date": new Date('2026-08-03T00:00:00.000Z'), "open": 182.99, "high": 183.03, "low": 181.76, "close": 181.94, "volume": 2892428 },
{ "date": new Date('2026-08-04T00:00:00.000Z'), "open": 181.94, "high": 184.62, "low": 181.8, "close": 182.87, "volume": 3059787 },
{ "date": new Date('2026-08-05T00:00:00.000Z'), "open": 182.87, "high": 183.86, "low": 179.61, "close": 180.65, "volume": 3153744 },
{ "date": new Date('2026-08-06T00:00:00.000Z'), "open": 180.65, "high": 183.48, "low": 180.36, "close": 183.38, "volume": 2096144 },
{ "date": new Date('2026-08-07T00:00:00.000Z'), "open": 183.38, "high": 183.72, "low": 179.24, "close": 181.35, "volume": 2428129 },
{ "date": new Date('2026-08-08T00:00:00.000Z'), "open": 181.35, "high": 183.15, "low": 178.87, "close": 181.68, "volume": 1957201 },
{ "date": new Date('2026-08-09T00:00:00.000Z'), "open": 181.68, "high": 184.48, "low": 180.15, "close": 184.09, "volume": 3131278 },
{ "date": new Date('2026-08-10T00:00:00.000Z'), "open": 184.09, "high": 187.25, "low": 182.16, "close": 184.76, "volume": 1986018 },
{ "date": new Date('2026-08-11T00:00:00.000Z'), "open": 184.76, "high": 185.27, "low": 181.34, "close": 184.06, "volume": 2629438 },
{ "date": new Date('2026-08-12T00:00:00.000Z'), "open": 184.06, "high": 185.48, "low": 181.89, "close": 182.38, "volume": 2086285 },
{ "date": new Date('2026-08-13T00:00:00.000Z'), "open": 182.38, "high": 185.11, "low": 180.61, "close": 183.66, "volume": 2860446 },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "open": 183.66, "high": 184.63, "low": 180.29, "close": 181.67, "volume": 2398495 },
{ "date": new Date('2026-08-15T00:00:00.000Z'), "open": 181.67, "high": 185.05, "low": 179.28, "close": 184.46, "volume": 2448935 },
{ "date": new Date('2026-08-16T00:00:00.000Z'), "open": 184.46, "high": 187.8, "low": 182.88, "close": 186.13, "volume": 2425201 },
{ "date": new Date('2026-08-17T00:00:00.000Z'), "open": 186.13, "high": 188.94, "low": 184.01, "close": 184.01, "volume": 2897024 },
{ "date": new Date('2026-08-18T00:00:00.000Z'), "open": 184.01, "high": 185.14, "low": 181.96, "close": 185.05, "volume": 2346585 },
{ "date": new Date('2026-08-19T00:00:00.000Z'), "open": 185.05, "high": 187.56, "low": 181.6, "close": 183.2, "volume": 1782162 },
{ "date": new Date('2026-08-20T00:00:00.000Z'), "open": 183.2, "high": 183.37, "low": 181.1, "close": 182.24, "volume": 3222334 },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "open": 182.24, "high": 187.12, "low": 180.33, "close": 184.51, "volume": 2058942 },
{ "date": new Date('2026-08-22T00:00:00.000Z'), "open": 184.51, "high": 187.36, "low": 184.49, "close": 186.44, "volume": 1849602 },
{ "date": new Date('2026-08-23T00:00:00.000Z'), "open": 186.44, "high": 189.61, "low": 183.73, "close": 188.9, "volume": 1968815 },
{ "date": new Date('2026-08-24T00:00:00.000Z'), "open": 188.9, "high": 192.67, "low": 188.31, "close": 191.85, "volume": 3047593 },
{ "date": new Date('2026-08-25T00:00:00.000Z'), "open": 191.85, "high": 194.69, "low": 188.25, "close": 190.53, "volume": 1890866 },
{ "date": new Date('2026-08-26T00:00:00.000Z'), "open": 190.53, "high": 192.03, "low": 188.23, "close": 190.78, "volume": 1826419 },
{ "date": new Date('2026-08-27T00:00:00.000Z'), "open": 190.78, "high": 196.36, "low": 190.07, "close": 193.85, "volume": 2686171 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "open": 193.85, "high": 197.11, "low": 192.05, "close": 194.2, "volume": 2566984 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "open": 194.2, "high": 194.38, "low": 191.92, "close": 192.45, "volume": 2585676 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "open": 192.45, "high": 192.6, "low": 190.83, "close": 191.48, "volume": 2902453 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "open": 191.48, "high": 195.18, "low": 190.07, "close": 194.15, "volume": 2226035 },
{ "date": new Date('2026-09-01T00:00:00.000Z'), "open": 194.15, "high": 194.96, "low": 191.2, "close": 194.68, "volume": 2865378 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "open": 194.68, "high": 195.97, "low": 191.95, "close": 192.18, "volume": 3179562 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "open": 192.18, "high": 197.54, "low": 190.1, "close": 195.29, "volume": 2203328 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "open": 195.29, "high": 200.11, "low": 193.34, "close": 197.72, "volume": 3287887 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "open": 197.72, "high": 202.47, "low": 196.55, "close": 200.86, "volume": 2108982 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "open": 200.86, "high": 202.44, "low": 200.14, "close": 201.7, "volume": 3050788 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "open": 201.7, "high": 206.09, "low": 201.08, "close": 203.76, "volume": 3160303 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "open": 203.76, "high": 205.09, "low": 203.28, "close": 203.62, "volume": 1547552 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "open": 203.62, "high": 206.45, "low": 199.93, "close": 200.54, "volume": 2419421 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "open": 200.54, "high": 203.41, "low": 196.4, "close": 199.31, "volume": 2137922 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "open": 199.31, "high": 201.44, "low": 197.01, "close": 197.94, "volume": 2856143 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "open": 197.94, "high": 200.87, "low": 193.01, "close": 195.54, "volume": 2016849 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "open": 195.54, "high": 197.51, "low": 192.95, "close": 196.79, "volume": 2621817 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "open": 196.79, "high": 199.2, "low": 194.82, "close": 197.52, "volume": 3033046 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "open": 197.52, "high": 203.69, "low": 197, "close": 200.66, "volume": 3041051 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "open": 200.66, "high": 204.11, "low": 198.61, "close": 203.59, "volume": 2082501 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "open": 203.59, "high": 208.28, "low": 201.87, "close": 205.27, "volume": 3222974 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "open": 205.27, "high": 206.64, "low": 203, "close": 203.49, "volume": 2462821 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "open": 203.49, "high": 204.33, "low": 198.71, "close": 200.51, "volume": 2368043 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "open": 200.51, "high": 204.21, "low": 199.53, "close": 204.04, "volume": 2964809 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "open": 204.04, "high": 205.6, "low": 199.82, "close": 201.65, "volume": 3263425 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "open": 201.65, "high": 206.26, "low": 198.81, "close": 203.2, "volume": 3180001 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "open": 203.2, "high": 206.48, "low": 200.12, "close": 205.46, "volume": 2041039 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "open": 205.46, "high": 208.24, "low": 202.34, "close": 203.24, "volume": 2468141 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "open": 203.24, "high": 206, "low": 202.82, "close": 205.56, "volume": 2886985 },
] },
{ "id": "1y", "label": "1Y", "data": [
{ "date": new Date('2025-09-26T00:00:00.000Z'), "open": 168, "high": 169.62, "low": 166.44, "close": 168.25, "volume": 2376004 },
{ "date": new Date('2025-09-27T00:00:00.000Z'), "open": 168.25, "high": 171.85, "low": 168.04, "close": 170.44, "volume": 2774560 },
{ "date": new Date('2025-09-28T00:00:00.000Z'), "open": 170.44, "high": 172.44, "low": 169.19, "close": 171.26, "volume": 2944011 },
{ "date": new Date('2025-09-29T00:00:00.000Z'), "open": 171.26, "high": 173.02, "low": 169.21, "close": 170.99, "volume": 1658505 },
{ "date": new Date('2025-09-30T00:00:00.000Z'), "open": 170.99, "high": 171.71, "low": 168.29, "close": 169.32, "volume": 2375766 },
{ "date": new Date('2025-10-01T00:00:00.000Z'), "open": 169.32, "high": 170.32, "low": 167.77, "close": 169.99, "volume": 2460006 },
{ "date": new Date('2025-10-02T00:00:00.000Z'), "open": 169.99, "high": 172.19, "low": 167.63, "close": 169.72, "volume": 2680722 },
{ "date": new Date('2025-10-03T00:00:00.000Z'), "open": 169.72, "high": 171.34, "low": 168.22, "close": 168.87, "volume": 1631238 },
{ "date": new Date('2025-10-04T00:00:00.000Z'), "open": 168.87, "high": 173, "low": 168.1, "close": 170.45, "volume": 1971537 },
{ "date": new Date('2025-10-05T00:00:00.000Z'), "open": 170.45, "high": 172.98, "low": 169.01, "close": 172.07, "volume": 2698383 },
{ "date": new Date('2025-10-06T00:00:00.000Z'), "open": 172.07, "high": 174.68, "low": 169.83, "close": 174.3, "volume": 3257688 },
{ "date": new Date('2025-10-07T00:00:00.000Z'), "open": 174.3, "high": 174.36, "low": 173.62, "close": 173.82, "volume": 2850391 },
{ "date": new Date('2025-10-08T00:00:00.000Z'), "open": 173.82, "high": 175.42, "low": 173.1, "close": 174.02, "volume": 2211865 },
{ "date": new Date('2025-10-09T00:00:00.000Z'), "open": 174.02, "high": 175.86, "low": 172.3, "close": 175.62, "volume": 1792415 },
{ "date": new Date('2025-10-10T00:00:00.000Z'), "open": 175.62, "high": 177.32, "low": 172.86, "close": 175.5, "volume": 2068163 },
{ "date": new Date('2025-10-11T00:00:00.000Z'), "open": 175.5, "high": 176.46, "low": 175.37, "close": 175.51, "volume": 2555075 },
{ "date": new Date('2025-10-12T00:00:00.000Z'), "open": 175.51, "high": 177.55, "low": 174.44, "close": 175.24, "volume": 2317847 },
{ "date": new Date('2025-10-13T00:00:00.000Z'), "open": 175.24, "high": 177.5, "low": 174.12, "close": 174.55, "volume": 1690321 },
{ "date": new Date('2025-10-14T00:00:00.000Z'), "open": 174.55, "high": 177.21, "low": 174.22, "close": 175.53, "volume": 2183688 },
{ "date": new Date('2025-10-15T00:00:00.000Z'), "open": 175.53, "high": 178.05, "low": 172.73, "close": 175.01, "volume": 2506047 },
{ "date": new Date('2025-10-16T00:00:00.000Z'), "open": 175.01, "high": 177.47, "low": 173.12, "close": 174.69, "volume": 2129860 },
{ "date": new Date('2025-10-17T00:00:00.000Z'), "open": 174.69, "high": 176.07, "low": 173.74, "close": 173.76, "volume": 3030574 },
{ "date": new Date('2025-10-18T00:00:00.000Z'), "open": 173.76, "high": 174.84, "low": 172.47, "close": 172.79, "volume": 1694594 },
{ "date": new Date('2025-10-19T00:00:00.000Z'), "open": 172.79, "high": 175.89, "low": 171.43, "close": 174.43, "volume": 1904016 },
{ "date": new Date('2025-10-20T00:00:00.000Z'), "open": 174.43, "high": 176.65, "low": 172.07, "close": 174.99, "volume": 3072627 },
{ "date": new Date('2025-10-21T00:00:00.000Z'), "open": 174.99, "high": 177.4, "low": 173.45, "close": 175.77, "volume": 2331782 },
{ "date": new Date('2025-10-22T00:00:00.000Z'), "open": 175.77, "high": 177.53, "low": 171.82, "close": 173.55, "volume": 3539201 },
{ "date": new Date('2025-10-23T00:00:00.000Z'), "open": 173.55, "high": 175.34, "low": 173.18, "close": 174.98, "volume": 2764322 },
{ "date": new Date('2025-10-24T00:00:00.000Z'), "open": 174.98, "high": 178.92, "low": 172.51, "close": 177.99, "volume": 2693639 },
{ "date": new Date('2025-10-25T00:00:00.000Z'), "open": 177.99, "high": 181.55, "low": 177.79, "close": 179.76, "volume": 2231591 },
{ "date": new Date('2025-10-26T00:00:00.000Z'), "open": 179.76, "high": 182.32, "low": 178.03, "close": 180.95, "volume": 1985808 },
{ "date": new Date('2025-10-27T00:00:00.000Z'), "open": 180.95, "high": 183.37, "low": 180.7, "close": 182.49, "volume": 2616956 },
{ "date": new Date('2025-10-28T00:00:00.000Z'), "open": 182.49, "high": 182.99, "low": 179.67, "close": 181.94, "volume": 3020438 },
{ "date": new Date('2025-10-29T00:00:00.000Z'), "open": 181.94, "high": 183.69, "low": 180.74, "close": 183.68, "volume": 3161692 },
{ "date": new Date('2025-10-30T00:00:00.000Z'), "open": 183.68, "high": 186.28, "low": 181.91, "close": 184.3, "volume": 1467567 },
{ "date": new Date('2025-10-31T00:00:00.000Z'), "open": 184.3, "high": 185.85, "low": 183.84, "close": 184.46, "volume": 2714578 },
{ "date": new Date('2025-11-01T00:00:00.000Z'), "open": 184.46, "high": 184.7, "low": 179.14, "close": 181.91, "volume": 2946728 },
{ "date": new Date('2025-11-02T00:00:00.000Z'), "open": 181.91, "high": 185.7, "low": 179.36, "close": 183.36, "volume": 3313196 },
{ "date": new Date('2025-11-03T00:00:00.000Z'), "open": 183.36, "high": 183.83, "low": 179.09, "close": 180.74, "volume": 2600538 },
{ "date": new Date('2025-11-04T00:00:00.000Z'), "open": 180.74, "high": 182.21, "low": 180.27, "close": 180.41, "volume": 1501013 },
{ "date": new Date('2025-11-05T00:00:00.000Z'), "open": 180.41, "high": 181.16, "low": 179.21, "close": 180.36, "volume": 2552203 },
{ "date": new Date('2025-11-06T00:00:00.000Z'), "open": 180.36, "high": 181.29, "low": 178.39, "close": 180.01, "volume": 2030022 },
{ "date": new Date('2025-11-07T00:00:00.000Z'), "open": 180.01, "high": 183.92, "low": 178.78, "close": 183.09, "volume": 2472445 },
{ "date": new Date('2025-11-08T00:00:00.000Z'), "open": 183.09, "high": 185.31, "low": 181.52, "close": 184.42, "volume": 2713760 },
{ "date": new Date('2025-11-09T00:00:00.000Z'), "open": 184.42, "high": 184.79, "low": 181.02, "close": 181.48, "volume": 3388796 },
{ "date": new Date('2025-11-10T00:00:00.000Z'), "open": 181.48, "high": 183.75, "low": 178.88, "close": 179.41, "volume": 2874434 },
{ "date": new Date('2025-11-11T00:00:00.000Z'), "open": 179.41, "high": 183.63, "low": 177.18, "close": 181.58, "volume": 2008713 },
{ "date": new Date('2025-11-12T00:00:00.000Z'), "open": 181.58, "high": 183.64, "low": 178.63, "close": 179.22, "volume": 2070968 },
{ "date": new Date('2025-11-13T00:00:00.000Z'), "open": 179.22, "high": 179.48, "low": 176.03, "close": 178.44, "volume": 2581175 },
{ "date": new Date('2025-11-14T00:00:00.000Z'), "open": 178.44, "high": 181.55, "low": 176.37, "close": 179.96, "volume": 2874984 },
{ "date": new Date('2025-11-15T00:00:00.000Z'), "open": 179.96, "high": 182.06, "low": 178.81, "close": 179.43, "volume": 1790012 },
{ "date": new Date('2025-11-16T00:00:00.000Z'), "open": 179.43, "high": 181.15, "low": 177.39, "close": 177.41, "volume": 2753234 },
{ "date": new Date('2025-11-17T00:00:00.000Z'), "open": 177.41, "high": 182.8, "low": 176, "close": 180.41, "volume": 3521242 },
{ "date": new Date('2025-11-18T00:00:00.000Z'), "open": 180.41, "high": 181.86, "low": 175.78, "close": 177.87, "volume": 2351223 },
{ "date": new Date('2025-11-19T00:00:00.000Z'), "open": 177.87, "high": 181.37, "low": 175.49, "close": 180.98, "volume": 2868754 },
{ "date": new Date('2025-11-20T00:00:00.000Z'), "open": 180.98, "high": 186.59, "low": 179.9, "close": 183.8, "volume": 2770997 },
{ "date": new Date('2025-11-21T00:00:00.000Z'), "open": 183.8, "high": 184.08, "low": 183.08, "close": 183.6, "volume": 1526430 },
{ "date": new Date('2025-11-22T00:00:00.000Z'), "open": 183.6, "high": 186.24, "low": 179.71, "close": 181.24, "volume": 2836453 },
{ "date": new Date('2025-11-23T00:00:00.000Z'), "open": 181.24, "high": 183.83, "low": 179.57, "close": 179.79, "volume": 3070500 },
{ "date": new Date('2025-11-24T00:00:00.000Z'), "open": 179.79, "high": 179.96, "low": 177.39, "close": 178.59, "volume": 2247633 },
{ "date": new Date('2025-11-25T00:00:00.000Z'), "open": 178.59, "high": 179.61, "low": 176.26, "close": 176.61, "volume": 3306230 },
{ "date": new Date('2025-11-26T00:00:00.000Z'), "open": 176.61, "high": 178.54, "low": 173.93, "close": 177.29, "volume": 2070876 },
{ "date": new Date('2025-11-27T00:00:00.000Z'), "open": 177.29, "high": 179.39, "low": 176.59, "close": 177.91, "volume": 2318429 },
{ "date": new Date('2025-11-28T00:00:00.000Z'), "open": 177.91, "high": 181.65, "low": 176.62, "close": 180.82, "volume": 2708715 },
{ "date": new Date('2025-11-29T00:00:00.000Z'), "open": 180.82, "high": 181.47, "low": 177.01, "close": 178.74, "volume": 1851015 },
{ "date": new Date('2025-11-30T00:00:00.000Z'), "open": 178.74, "high": 180.77, "low": 176.05, "close": 176.48, "volume": 2225169 },
{ "date": new Date('2025-12-01T00:00:00.000Z'), "open": 176.48, "high": 178.59, "low": 174.66, "close": 176.28, "volume": 2384801 },
{ "date": new Date('2025-12-02T00:00:00.000Z'), "open": 176.28, "high": 178.57, "low": 174.24, "close": 177.55, "volume": 3179221 },
{ "date": new Date('2025-12-03T00:00:00.000Z'), "open": 177.55, "high": 179.48, "low": 176.5, "close": 176.73, "volume": 1738894 },
{ "date": new Date('2025-12-04T00:00:00.000Z'), "open": 176.73, "high": 178.93, "low": 176.46, "close": 177.08, "volume": 2952165 },
{ "date": new Date('2025-12-05T00:00:00.000Z'), "open": 177.08, "high": 180.15, "low": 174.65, "close": 179.78, "volume": 2621607 },
{ "date": new Date('2025-12-06T00:00:00.000Z'), "open": 179.78, "high": 182.87, "low": 177.62, "close": 181.29, "volume": 3306391 },
{ "date": new Date('2025-12-07T00:00:00.000Z'), "open": 181.29, "high": 181.91, "low": 180.28, "close": 181.16, "volume": 2551131 },
{ "date": new Date('2025-12-08T00:00:00.000Z'), "open": 181.16, "high": 182.78, "low": 179.17, "close": 182.64, "volume": 1877325 },
{ "date": new Date('2025-12-09T00:00:00.000Z'), "open": 182.64, "high": 184.75, "low": 181.21, "close": 182.41, "volume": 2968023 },
{ "date": new Date('2025-12-10T00:00:00.000Z'), "open": 182.41, "high": 184.47, "low": 182.15, "close": 184.13, "volume": 2009525 },
{ "date": new Date('2025-12-11T00:00:00.000Z'), "open": 184.13, "high": 186.79, "low": 180.62, "close": 181.32, "volume": 3070357 },
{ "date": new Date('2025-12-12T00:00:00.000Z'), "open": 181.32, "high": 182.22, "low": 178.28, "close": 180.26, "volume": 2842411 },
{ "date": new Date('2025-12-13T00:00:00.000Z'), "open": 180.26, "high": 183.85, "low": 178.73, "close": 181.15, "volume": 2890598 },
{ "date": new Date('2025-12-14T00:00:00.000Z'), "open": 181.15, "high": 182.74, "low": 180.35, "close": 181.65, "volume": 2953104 },
{ "date": new Date('2025-12-15T00:00:00.000Z'), "open": 181.65, "high": 183.17, "low": 178.18, "close": 179.39, "volume": 2986255 },
{ "date": new Date('2025-12-16T00:00:00.000Z'), "open": 179.39, "high": 180.29, "low": 177.55, "close": 179.77, "volume": 1881763 },
{ "date": new Date('2025-12-17T00:00:00.000Z'), "open": 179.77, "high": 180.04, "low": 176.33, "close": 178.75, "volume": 2235638 },
{ "date": new Date('2025-12-18T00:00:00.000Z'), "open": 178.75, "high": 180.31, "low": 175.3, "close": 176.52, "volume": 2197598 },
{ "date": new Date('2025-12-19T00:00:00.000Z'), "open": 176.52, "high": 176.68, "low": 173.05, "close": 174.09, "volume": 3446510 },
{ "date": new Date('2025-12-20T00:00:00.000Z'), "open": 174.09, "high": 176.51, "low": 172.89, "close": 173.8, "volume": 1974833 },
{ "date": new Date('2025-12-21T00:00:00.000Z'), "open": 173.8, "high": 174.65, "low": 172.82, "close": 174.63, "volume": 2455323 },
{ "date": new Date('2025-12-22T00:00:00.000Z'), "open": 174.63, "high": 178.48, "low": 172.96, "close": 176.56, "volume": 3402154 },
{ "date": new Date('2025-12-23T00:00:00.000Z'), "open": 176.56, "high": 177.95, "low": 176.32, "close": 177.5, "volume": 1768634 },
{ "date": new Date('2025-12-24T00:00:00.000Z'), "open": 177.5, "high": 179.81, "low": 175.57, "close": 175.99, "volume": 1909374 },
{ "date": new Date('2025-12-25T00:00:00.000Z'), "open": 175.99, "high": 178.24, "low": 171.59, "close": 173.57, "volume": 1948920 },
{ "date": new Date('2025-12-26T00:00:00.000Z'), "open": 173.57, "high": 173.6, "low": 172.38, "close": 172.98, "volume": 2815526 },
{ "date": new Date('2025-12-27T00:00:00.000Z'), "open": 172.98, "high": 173.01, "low": 172.87, "close": 172.99, "volume": 1373445 },
{ "date": new Date('2025-12-28T00:00:00.000Z'), "open": 172.99, "high": 174.32, "low": 172.41, "close": 172.45, "volume": 2913342 },
{ "date": new Date('2025-12-29T00:00:00.000Z'), "open": 172.45, "high": 175.69, "low": 171.53, "close": 175.04, "volume": 2157600 },
{ "date": new Date('2025-12-30T00:00:00.000Z'), "open": 175.04, "high": 175.12, "low": 172.06, "close": 173.16, "volume": 3055756 },
{ "date": new Date('2025-12-31T00:00:00.000Z'), "open": 173.16, "high": 175.99, "low": 170.89, "close": 174.94, "volume": 2552465 },
{ "date": new Date('2026-01-01T00:00:00.000Z'), "open": 174.94, "high": 176.6, "low": 172.25, "close": 173.98, "volume": 2670145 },
{ "date": new Date('2026-01-02T00:00:00.000Z'), "open": 173.98, "high": 175.86, "low": 172.3, "close": 173.53, "volume": 2114092 },
{ "date": new Date('2026-01-03T00:00:00.000Z'), "open": 173.53, "high": 176.09, "low": 172.42, "close": 173.23, "volume": 2459980 },
{ "date": new Date('2026-01-04T00:00:00.000Z'), "open": 173.23, "high": 174.91, "low": 170.51, "close": 170.84, "volume": 2974654 },
{ "date": new Date('2026-01-05T00:00:00.000Z'), "open": 170.84, "high": 172.95, "low": 167.51, "close": 169.4, "volume": 2015939 },
{ "date": new Date('2026-01-06T00:00:00.000Z'), "open": 169.4, "high": 173.31, "low": 168.47, "close": 172.22, "volume": 2394684 },
{ "date": new Date('2026-01-07T00:00:00.000Z'), "open": 172.22, "high": 174.55, "low": 169.19, "close": 169.54, "volume": 2857399 },
{ "date": new Date('2026-01-08T00:00:00.000Z'), "open": 169.54, "high": 174.08, "low": 169.15, "close": 171.76, "volume": 3409348 },
{ "date": new Date('2026-01-09T00:00:00.000Z'), "open": 171.76, "high": 173.22, "low": 170.42, "close": 171.35, "volume": 2012173 },
{ "date": new Date('2026-01-10T00:00:00.000Z'), "open": 171.35, "high": 171.42, "low": 168.49, "close": 169.17, "volume": 1972764 },
{ "date": new Date('2026-01-11T00:00:00.000Z'), "open": 169.17, "high": 170.75, "low": 166.98, "close": 168.18, "volume": 1988412 },
{ "date": new Date('2026-01-12T00:00:00.000Z'), "open": 168.18, "high": 170.09, "low": 166.22, "close": 168.48, "volume": 2961721 },
{ "date": new Date('2026-01-13T00:00:00.000Z'), "open": 168.48, "high": 169.6, "low": 166.59, "close": 166.89, "volume": 2902902 },
{ "date": new Date('2026-01-14T00:00:00.000Z'), "open": 166.89, "high": 167.29, "low": 164.38, "close": 166.01, "volume": 1985029 },
{ "date": new Date('2026-01-15T00:00:00.000Z'), "open": 166.01, "high": 167.68, "low": 163.79, "close": 164.28, "volume": 2170519 },
{ "date": new Date('2026-01-16T00:00:00.000Z'), "open": 164.28, "high": 164.31, "low": 162.74, "close": 162.97, "volume": 1761474 },
{ "date": new Date('2026-01-17T00:00:00.000Z'), "open": 162.97, "high": 164.26, "low": 161.36, "close": 162.17, "volume": 3161593 },
{ "date": new Date('2026-01-18T00:00:00.000Z'), "open": 162.17, "high": 165.35, "low": 161.46, "close": 163.56, "volume": 2815391 },
{ "date": new Date('2026-01-19T00:00:00.000Z'), "open": 163.56, "high": 165.8, "low": 162.33, "close": 163.3, "volume": 2675676 },
{ "date": new Date('2026-01-20T00:00:00.000Z'), "open": 163.3, "high": 163.91, "low": 159.37, "close": 161.68, "volume": 2235379 },
{ "date": new Date('2026-01-21T00:00:00.000Z'), "open": 161.68, "high": 163.81, "low": 157.37, "close": 159.49, "volume": 2333442 },
{ "date": new Date('2026-01-22T00:00:00.000Z'), "open": 159.49, "high": 159.85, "low": 155.79, "close": 156.97, "volume": 2070253 },
{ "date": new Date('2026-01-23T00:00:00.000Z'), "open": 156.97, "high": 159.8, "low": 155.35, "close": 158.09, "volume": 2511882 },
{ "date": new Date('2026-01-24T00:00:00.000Z'), "open": 158.09, "high": 160.35, "low": 154.41, "close": 156.72, "volume": 2787778 },
{ "date": new Date('2026-01-25T00:00:00.000Z'), "open": 156.72, "high": 157.51, "low": 154.13, "close": 154.87, "volume": 2682325 },
{ "date": new Date('2026-01-26T00:00:00.000Z'), "open": 154.87, "high": 158.95, "low": 154.73, "close": 156.67, "volume": 2287307 },
{ "date": new Date('2026-01-27T00:00:00.000Z'), "open": 156.67, "high": 158.93, "low": 154.86, "close": 156.28, "volume": 2212214 },
{ "date": new Date('2026-01-28T00:00:00.000Z'), "open": 156.28, "high": 157.82, "low": 153.26, "close": 154.6, "volume": 2469048 },
{ "date": new Date('2026-01-29T00:00:00.000Z'), "open": 154.6, "high": 158, "low": 152.35, "close": 156.89, "volume": 2202094 },
{ "date": new Date('2026-01-30T00:00:00.000Z'), "open": 156.89, "high": 158.34, "low": 153.8, "close": 155.69, "volume": 2188116 },
{ "date": new Date('2026-01-31T00:00:00.000Z'), "open": 155.69, "high": 155.82, "low": 153.88, "close": 154.68, "volume": 3000837 },
{ "date": new Date('2026-02-01T00:00:00.000Z'), "open": 154.68, "high": 157.63, "low": 153.65, "close": 156.94, "volume": 2683389 },
{ "date": new Date('2026-02-02T00:00:00.000Z'), "open": 156.94, "high": 157.92, "low": 154.85, "close": 156.59, "volume": 1596920 },
{ "date": new Date('2026-02-03T00:00:00.000Z'), "open": 156.59, "high": 157.14, "low": 153.58, "close": 155.85, "volume": 1792765 },
{ "date": new Date('2026-02-04T00:00:00.000Z'), "open": 155.85, "high": 157.23, "low": 152.91, "close": 153.45, "volume": 1994696 },
{ "date": new Date('2026-02-05T00:00:00.000Z'), "open": 153.45, "high": 156.98, "low": 153.08, "close": 155.33, "volume": 3111199 },
{ "date": new Date('2026-02-06T00:00:00.000Z'), "open": 155.33, "high": 155.5, "low": 152.48, "close": 152.91, "volume": 2063716 },
{ "date": new Date('2026-02-07T00:00:00.000Z'), "open": 152.91, "high": 155.09, "low": 148.54, "close": 150.54, "volume": 3294200 },
{ "date": new Date('2026-02-08T00:00:00.000Z'), "open": 150.54, "high": 152.85, "low": 148.76, "close": 151.46, "volume": 2024517 },
{ "date": new Date('2026-02-09T00:00:00.000Z'), "open": 151.46, "high": 152.36, "low": 149.06, "close": 149.32, "volume": 2395854 },
{ "date": new Date('2026-02-10T00:00:00.000Z'), "open": 149.32, "high": 149.97, "low": 148.73, "close": 149.03, "volume": 2859938 },
{ "date": new Date('2026-02-11T00:00:00.000Z'), "open": 149.03, "high": 151.09, "low": 147.39, "close": 149.09, "volume": 1576157 },
{ "date": new Date('2026-02-12T00:00:00.000Z'), "open": 149.09, "high": 150.87, "low": 149.05, "close": 149.35, "volume": 2056184 },
{ "date": new Date('2026-02-13T00:00:00.000Z'), "open": 149.35, "high": 152.44, "low": 148.48, "close": 150.54, "volume": 2730759 },
{ "date": new Date('2026-02-14T00:00:00.000Z'), "open": 150.54, "high": 151.03, "low": 149.1, "close": 150.42, "volume": 2996948 },
{ "date": new Date('2026-02-15T00:00:00.000Z'), "open": 150.42, "high": 150.6, "low": 148.32, "close": 149.07, "volume": 2528822 },
{ "date": new Date('2026-02-16T00:00:00.000Z'), "open": 149.07, "high": 150.8, "low": 146.04, "close": 148.24, "volume": 2264302 },
{ "date": new Date('2026-02-17T00:00:00.000Z'), "open": 148.24, "high": 148.52, "low": 146.16, "close": 147.73, "volume": 2201103 },
{ "date": new Date('2026-02-18T00:00:00.000Z'), "open": 147.73, "high": 148.01, "low": 146.59, "close": 146.64, "volume": 2586394 },
{ "date": new Date('2026-02-19T00:00:00.000Z'), "open": 146.64, "high": 147.99, "low": 144.47, "close": 145.29, "volume": 3155410 },
{ "date": new Date('2026-02-20T00:00:00.000Z'), "open": 145.29, "high": 147.38, "low": 144.5, "close": 147.14, "volume": 2544257 },
{ "date": new Date('2026-02-21T00:00:00.000Z'), "open": 147.14, "high": 147.48, "low": 144.35, "close": 146.17, "volume": 1961931 },
{ "date": new Date('2026-02-22T00:00:00.000Z'), "open": 146.17, "high": 146.85, "low": 145.02, "close": 146.65, "volume": 2479013 },
{ "date": new Date('2026-02-23T00:00:00.000Z'), "open": 146.65, "high": 149.05, "low": 145.57, "close": 147.95, "volume": 3281713 },
{ "date": new Date('2026-02-24T00:00:00.000Z'), "open": 147.95, "high": 149.61, "low": 145.35, "close": 146.29, "volume": 3066156 },
{ "date": new Date('2026-02-25T00:00:00.000Z'), "open": 146.29, "high": 148.62, "low": 145.15, "close": 146.95, "volume": 2677601 },
{ "date": new Date('2026-02-26T00:00:00.000Z'), "open": 146.95, "high": 147.62, "low": 143.72, "close": 144.66, "volume": 3110522 },
{ "date": new Date('2026-02-27T00:00:00.000Z'), "open": 144.66, "high": 146.12, "low": 142.95, "close": 144.23, "volume": 2550500 },
{ "date": new Date('2026-02-28T00:00:00.000Z'), "open": 144.23, "high": 145.97, "low": 142.59, "close": 145.96, "volume": 3144137 },
{ "date": new Date('2026-03-01T00:00:00.000Z'), "open": 145.96, "high": 147.66, "low": 145.54, "close": 146.36, "volume": 1701330 },
{ "date": new Date('2026-03-02T00:00:00.000Z'), "open": 146.36, "high": 147.07, "low": 145.37, "close": 146.7, "volume": 2106014 },
{ "date": new Date('2026-03-03T00:00:00.000Z'), "open": 146.7, "high": 146.92, "low": 144.64, "close": 145.36, "volume": 3008395 },
{ "date": new Date('2026-03-04T00:00:00.000Z'), "open": 145.36, "high": 148.16, "low": 145.1, "close": 146.29, "volume": 1866897 },
{ "date": new Date('2026-03-05T00:00:00.000Z'), "open": 146.29, "high": 147.59, "low": 142.01, "close": 144.11, "volume": 3118656 },
{ "date": new Date('2026-03-06T00:00:00.000Z'), "open": 144.11, "high": 144.82, "low": 141.68, "close": 142.71, "volume": 1886003 },
{ "date": new Date('2026-03-07T00:00:00.000Z'), "open": 142.71, "high": 144.75, "low": 141.62, "close": 142.75, "volume": 2058656 },
{ "date": new Date('2026-03-08T00:00:00.000Z'), "open": 142.75, "high": 144.17, "low": 139.85, "close": 140.87, "volume": 3564841 },
{ "date": new Date('2026-03-09T00:00:00.000Z'), "open": 140.87, "high": 141.22, "low": 138.3, "close": 140.29, "volume": 2404470 },
{ "date": new Date('2026-03-10T00:00:00.000Z'), "open": 140.29, "high": 140.72, "low": 138.49, "close": 139.15, "volume": 2596164 },
{ "date": new Date('2026-03-11T00:00:00.000Z'), "open": 139.15, "high": 142.69, "low": 138.73, "close": 140.58, "volume": 2744217 },
{ "date": new Date('2026-03-12T00:00:00.000Z'), "open": 140.58, "high": 143.13, "low": 138.53, "close": 141.85, "volume": 2583628 },
{ "date": new Date('2026-03-13T00:00:00.000Z'), "open": 141.85, "high": 144.46, "low": 141.71, "close": 143.7, "volume": 3505747 },
{ "date": new Date('2026-03-14T00:00:00.000Z'), "open": 143.7, "high": 144.75, "low": 143.49, "close": 144.51, "volume": 1798013 },
{ "date": new Date('2026-03-15T00:00:00.000Z'), "open": 144.51, "high": 146.02, "low": 142.27, "close": 143.76, "volume": 2189504 },
{ "date": new Date('2026-03-16T00:00:00.000Z'), "open": 143.76, "high": 145.63, "low": 142.25, "close": 144.22, "volume": 2133603 },
{ "date": new Date('2026-03-17T00:00:00.000Z'), "open": 144.22, "high": 145.99, "low": 142.01, "close": 142.34, "volume": 2820359 },
{ "date": new Date('2026-03-18T00:00:00.000Z'), "open": 142.34, "high": 146.51, "low": 140.17, "close": 144.6, "volume": 2747946 },
{ "date": new Date('2026-03-19T00:00:00.000Z'), "open": 144.6, "high": 146.67, "low": 142.36, "close": 144, "volume": 2751792 },
{ "date": new Date('2026-03-20T00:00:00.000Z'), "open": 144, "high": 146.39, "low": 143.41, "close": 146, "volume": 3043261 },
{ "date": new Date('2026-03-21T00:00:00.000Z'), "open": 146, "high": 147.03, "low": 143.55, "close": 145.05, "volume": 2520335 },
{ "date": new Date('2026-03-22T00:00:00.000Z'), "open": 145.05, "high": 147.68, "low": 145.04, "close": 147.23, "volume": 3087607 },
{ "date": new Date('2026-03-23T00:00:00.000Z'), "open": 147.23, "high": 149.76, "low": 145.08, "close": 148.29, "volume": 1950152 },
{ "date": new Date('2026-03-24T00:00:00.000Z'), "open": 148.29, "high": 150.56, "low": 145.23, "close": 146.67, "volume": 2224052 },
{ "date": new Date('2026-03-25T00:00:00.000Z'), "open": 146.67, "high": 148.3, "low": 144.29, "close": 145.82, "volume": 3168676 },
{ "date": new Date('2026-03-26T00:00:00.000Z'), "open": 145.82, "high": 146.53, "low": 144.94, "close": 145.14, "volume": 1600881 },
{ "date": new Date('2026-03-27T00:00:00.000Z'), "open": 145.14, "high": 146.06, "low": 143.4, "close": 145.73, "volume": 2635213 },
{ "date": new Date('2026-03-28T00:00:00.000Z'), "open": 145.73, "high": 148.07, "low": 145.41, "close": 147.17, "volume": 2899898 },
{ "date": new Date('2026-03-29T00:00:00.000Z'), "open": 147.17, "high": 151.54, "low": 146.53, "close": 149.83, "volume": 2585536 },
{ "date": new Date('2026-03-30T00:00:00.000Z'), "open": 149.83, "high": 150.65, "low": 146.57, "close": 148.2, "volume": 1801152 },
{ "date": new Date('2026-03-31T00:00:00.000Z'), "open": 148.2, "high": 148.77, "low": 146.89, "close": 148.5, "volume": 2870322 },
{ "date": new Date('2026-04-01T00:00:00.000Z'), "open": 148.5, "high": 153.27, "low": 147.82, "close": 151.01, "volume": 3444678 },
{ "date": new Date('2026-04-02T00:00:00.000Z'), "open": 151.01, "high": 152.29, "low": 148.98, "close": 151.21, "volume": 1561281 },
{ "date": new Date('2026-04-03T00:00:00.000Z'), "open": 151.21, "high": 154.03, "low": 149.25, "close": 152.63, "volume": 2220081 },
{ "date": new Date('2026-04-04T00:00:00.000Z'), "open": 152.63, "high": 152.79, "low": 149.52, "close": 151.13, "volume": 2781695 },
{ "date": new Date('2026-04-05T00:00:00.000Z'), "open": 151.13, "high": 154.6, "low": 150.87, "close": 153.81, "volume": 2867194 },
{ "date": new Date('2026-04-06T00:00:00.000Z'), "open": 153.81, "high": 157.44, "low": 152.33, "close": 156.09, "volume": 3444996 },
{ "date": new Date('2026-04-07T00:00:00.000Z'), "open": 156.09, "high": 156.68, "low": 154.82, "close": 156.57, "volume": 1744423 },
{ "date": new Date('2026-04-08T00:00:00.000Z'), "open": 156.57, "high": 157.78, "low": 153.72, "close": 155.24, "volume": 2450699 },
{ "date": new Date('2026-04-09T00:00:00.000Z'), "open": 155.24, "high": 155.25, "low": 152.91, "close": 153.65, "volume": 1987237 },
{ "date": new Date('2026-04-10T00:00:00.000Z'), "open": 153.65, "high": 156.22, "low": 152.27, "close": 154.39, "volume": 1666324 },
{ "date": new Date('2026-04-11T00:00:00.000Z'), "open": 154.39, "high": 155.51, "low": 153.82, "close": 155.36, "volume": 2021039 },
{ "date": new Date('2026-04-12T00:00:00.000Z'), "open": 155.36, "high": 155.75, "low": 155.11, "close": 155.29, "volume": 2937036 },
{ "date": new Date('2026-04-13T00:00:00.000Z'), "open": 155.29, "high": 155.56, "low": 151.57, "close": 153.7, "volume": 1996865 },
{ "date": new Date('2026-04-14T00:00:00.000Z'), "open": 153.7, "high": 156.04, "low": 151.32, "close": 151.8, "volume": 2238815 },
{ "date": new Date('2026-04-15T00:00:00.000Z'), "open": 151.8, "high": 155.39, "low": 150.25, "close": 153.74, "volume": 3217911 },
{ "date": new Date('2026-04-16T00:00:00.000Z'), "open": 153.74, "high": 157.57, "low": 151.84, "close": 155.24, "volume": 2119930 },
{ "date": new Date('2026-04-17T00:00:00.000Z'), "open": 155.24, "high": 156.06, "low": 152.91, "close": 154.93, "volume": 1760989 },
{ "date": new Date('2026-04-18T00:00:00.000Z'), "open": 154.93, "high": 156.61, "low": 151.45, "close": 152.56, "volume": 2411306 },
{ "date": new Date('2026-04-19T00:00:00.000Z'), "open": 152.56, "high": 153.69, "low": 148.84, "close": 150.35, "volume": 2106919 },
{ "date": new Date('2026-04-20T00:00:00.000Z'), "open": 150.35, "high": 153.5, "low": 150.2, "close": 152.49, "volume": 2449872 },
{ "date": new Date('2026-04-21T00:00:00.000Z'), "open": 152.49, "high": 154.63, "low": 150.52, "close": 150.85, "volume": 2773442 },
{ "date": new Date('2026-04-22T00:00:00.000Z'), "open": 150.85, "high": 152.73, "low": 148.78, "close": 150.74, "volume": 1461180 },
{ "date": new Date('2026-04-23T00:00:00.000Z'), "open": 150.74, "high": 153.37, "low": 149.77, "close": 153.34, "volume": 3687707 },
{ "date": new Date('2026-04-24T00:00:00.000Z'), "open": 153.34, "high": 153.34, "low": 150.12, "close": 152.09, "volume": 2527334 },
{ "date": new Date('2026-04-25T00:00:00.000Z'), "open": 152.09, "high": 153.71, "low": 150.52, "close": 152.37, "volume": 1983212 },
{ "date": new Date('2026-04-26T00:00:00.000Z'), "open": 152.37, "high": 154.61, "low": 150.07, "close": 152.73, "volume": 2228479 },
{ "date": new Date('2026-04-27T00:00:00.000Z'), "open": 152.73, "high": 156.76, "low": 152.42, "close": 154.44, "volume": 2173658 },
{ "date": new Date('2026-04-28T00:00:00.000Z'), "open": 154.44, "high": 155.74, "low": 152.48, "close": 155.66, "volume": 2669832 },
{ "date": new Date('2026-04-29T00:00:00.000Z'), "open": 155.66, "high": 158.19, "low": 154.64, "close": 156.77, "volume": 3039806 },
{ "date": new Date('2026-04-30T00:00:00.000Z'), "open": 156.77, "high": 160.39, "low": 154.5, "close": 159.22, "volume": 2032129 },
{ "date": new Date('2026-05-01T00:00:00.000Z'), "open": 159.22, "high": 159.61, "low": 156.08, "close": 157.01, "volume": 3142221 },
{ "date": new Date('2026-05-02T00:00:00.000Z'), "open": 157.01, "high": 157.59, "low": 154.3, "close": 155.92, "volume": 2751851 },
{ "date": new Date('2026-05-03T00:00:00.000Z'), "open": 155.92, "high": 159.53, "low": 153.9, "close": 158.46, "volume": 2063295 },
{ "date": new Date('2026-05-04T00:00:00.000Z'), "open": 158.46, "high": 161.28, "low": 157.89, "close": 160.86, "volume": 3193688 },
{ "date": new Date('2026-05-05T00:00:00.000Z'), "open": 160.86, "high": 163.29, "low": 158.21, "close": 160.34, "volume": 2776757 },
{ "date": new Date('2026-05-06T00:00:00.000Z'), "open": 160.34, "high": 162.91, "low": 158.24, "close": 160.84, "volume": 1530875 },
{ "date": new Date('2026-05-07T00:00:00.000Z'), "open": 160.84, "high": 165.76, "low": 159.81, "close": 163.66, "volume": 3272444 },
{ "date": new Date('2026-05-08T00:00:00.000Z'), "open": 163.66, "high": 167.1, "low": 162.88, "close": 165, "volume": 2914948 },
{ "date": new Date('2026-05-09T00:00:00.000Z'), "open": 165, "high": 166.61, "low": 163.64, "close": 164.19, "volume": 2912552 },
{ "date": new Date('2026-05-10T00:00:00.000Z'), "open": 164.19, "high": 166.67, "low": 162.65, "close": 162.88, "volume": 1857223 },
{ "date": new Date('2026-05-11T00:00:00.000Z'), "open": 162.88, "high": 163.4, "low": 161.22, "close": 163.06, "volume": 2688559 },
{ "date": new Date('2026-05-12T00:00:00.000Z'), "open": 163.06, "high": 167.26, "low": 161.86, "close": 164.94, "volume": 3262744 },
{ "date": new Date('2026-05-13T00:00:00.000Z'), "open": 164.94, "high": 169.28, "low": 163.15, "close": 167.47, "volume": 2715268 },
{ "date": new Date('2026-05-14T00:00:00.000Z'), "open": 167.47, "high": 169.14, "low": 166.23, "close": 167.62, "volume": 2496159 },
{ "date": new Date('2026-05-15T00:00:00.000Z'), "open": 167.62, "high": 169.78, "low": 166.89, "close": 169.28, "volume": 2835271 },
{ "date": new Date('2026-05-16T00:00:00.000Z'), "open": 169.28, "high": 170.41, "low": 166.83, "close": 168.98, "volume": 1851239 },
{ "date": new Date('2026-05-17T00:00:00.000Z'), "open": 168.98, "high": 172.53, "low": 167.83, "close": 170.99, "volume": 2175470 },
{ "date": new Date('2026-05-18T00:00:00.000Z'), "open": 170.99, "high": 173.45, "low": 168.74, "close": 169.09, "volume": 2317336 },
{ "date": new Date('2026-05-19T00:00:00.000Z'), "open": 169.09, "high": 172.51, "low": 166.85, "close": 170.96, "volume": 2279714 },
{ "date": new Date('2026-05-20T00:00:00.000Z'), "open": 170.96, "high": 173.64, "low": 169.41, "close": 171.33, "volume": 2598995 },
{ "date": new Date('2026-05-21T00:00:00.000Z'), "open": 171.33, "high": 173.01, "low": 169.05, "close": 170, "volume": 1941274 },
{ "date": new Date('2026-05-22T00:00:00.000Z'), "open": 170, "high": 170.87, "low": 167.4, "close": 170.01, "volume": 2223511 },
{ "date": new Date('2026-05-23T00:00:00.000Z'), "open": 170.01, "high": 170.91, "low": 166.5, "close": 168.73, "volume": 2776761 },
{ "date": new Date('2026-05-24T00:00:00.000Z'), "open": 168.73, "high": 169.99, "low": 166.96, "close": 167.73, "volume": 3029364 },
{ "date": new Date('2026-05-25T00:00:00.000Z'), "open": 167.73, "high": 171.03, "low": 166.9, "close": 169.8, "volume": 2426138 },
{ "date": new Date('2026-05-26T00:00:00.000Z'), "open": 169.8, "high": 170.23, "low": 168.44, "close": 169.91, "volume": 1479940 },
{ "date": new Date('2026-05-27T00:00:00.000Z'), "open": 169.91, "high": 171.32, "low": 166.65, "close": 167.8, "volume": 2339555 },
{ "date": new Date('2026-05-28T00:00:00.000Z'), "open": 167.8, "high": 169.88, "low": 165.53, "close": 168.8, "volume": 3143896 },
{ "date": new Date('2026-05-29T00:00:00.000Z'), "open": 168.8, "high": 172.53, "low": 167, "close": 171.42, "volume": 3569036 },
{ "date": new Date('2026-05-30T00:00:00.000Z'), "open": 171.42, "high": 172.42, "low": 171.38, "close": 171.52, "volume": 2395288 },
{ "date": new Date('2026-05-31T00:00:00.000Z'), "open": 171.52, "high": 174.19, "low": 170.56, "close": 171.94, "volume": 1990912 },
{ "date": new Date('2026-06-01T00:00:00.000Z'), "open": 171.94, "high": 173.36, "low": 171.9, "close": 172.14, "volume": 2707900 },
{ "date": new Date('2026-06-02T00:00:00.000Z'), "open": 172.14, "high": 174.94, "low": 171.29, "close": 174.9, "volume": 2731770 },
{ "date": new Date('2026-06-03T00:00:00.000Z'), "open": 174.9, "high": 178.13, "low": 172.81, "close": 176.92, "volume": 3194193 },
{ "date": new Date('2026-06-04T00:00:00.000Z'), "open": 176.92, "high": 178.26, "low": 173.44, "close": 174.62, "volume": 2227849 },
{ "date": new Date('2026-06-05T00:00:00.000Z'), "open": 174.62, "high": 174.99, "low": 171.99, "close": 172.53, "volume": 1952142 },
{ "date": new Date('2026-06-06T00:00:00.000Z'), "open": 172.53, "high": 172.9, "low": 169.67, "close": 172.05, "volume": 1483655 },
{ "date": new Date('2026-06-07T00:00:00.000Z'), "open": 172.05, "high": 173.81, "low": 170.31, "close": 170.99, "volume": 2016829 },
{ "date": new Date('2026-06-08T00:00:00.000Z'), "open": 170.99, "high": 174.14, "low": 169.52, "close": 173.4, "volume": 2847738 },
{ "date": new Date('2026-06-09T00:00:00.000Z'), "open": 173.4, "high": 174.82, "low": 171.09, "close": 172.73, "volume": 3025302 },
{ "date": new Date('2026-06-10T00:00:00.000Z'), "open": 172.73, "high": 175.24, "low": 169.06, "close": 171.38, "volume": 2619529 },
{ "date": new Date('2026-06-11T00:00:00.000Z'), "open": 171.38, "high": 173.96, "low": 168.95, "close": 168.98, "volume": 1944874 },
{ "date": new Date('2026-06-12T00:00:00.000Z'), "open": 168.98, "high": 171.8, "low": 168.17, "close": 171.24, "volume": 3509680 },
{ "date": new Date('2026-06-13T00:00:00.000Z'), "open": 171.24, "high": 174.44, "low": 170.79, "close": 172.07, "volume": 3186503 },
{ "date": new Date('2026-06-14T00:00:00.000Z'), "open": 172.07, "high": 173.69, "low": 167.88, "close": 170.2, "volume": 2170077 },
{ "date": new Date('2026-06-15T00:00:00.000Z'), "open": 170.2, "high": 175.03, "low": 169.27, "close": 172.5, "volume": 2721369 },
{ "date": new Date('2026-06-16T00:00:00.000Z'), "open": 172.5, "high": 176.4, "low": 171.91, "close": 174.49, "volume": 3009601 },
{ "date": new Date('2026-06-17T00:00:00.000Z'), "open": 174.49, "high": 176.68, "low": 173.6, "close": 174.02, "volume": 2714240 },
{ "date": new Date('2026-06-18T00:00:00.000Z'), "open": 174.02, "high": 178.82, "low": 172.25, "close": 176.38, "volume": 2488549 },
{ "date": new Date('2026-06-19T00:00:00.000Z'), "open": 176.38, "high": 179.52, "low": 173.8, "close": 178.3, "volume": 2184126 },
{ "date": new Date('2026-06-20T00:00:00.000Z'), "open": 178.3, "high": 179.44, "low": 177.72, "close": 178.06, "volume": 2206916 },
{ "date": new Date('2026-06-21T00:00:00.000Z'), "open": 178.06, "high": 179.65, "low": 175.56, "close": 176.36, "volume": 2968498 },
{ "date": new Date('2026-06-22T00:00:00.000Z'), "open": 176.36, "high": 178.75, "low": 173.65, "close": 173.66, "volume": 2018748 },
{ "date": new Date('2026-06-23T00:00:00.000Z'), "open": 173.66, "high": 175.77, "low": 173.28, "close": 173.29, "volume": 1493203 },
{ "date": new Date('2026-06-24T00:00:00.000Z'), "open": 173.29, "high": 174.25, "low": 171.2, "close": 174.17, "volume": 1677755 },
{ "date": new Date('2026-06-25T00:00:00.000Z'), "open": 174.17, "high": 176.49, "low": 172.14, "close": 174.18, "volume": 2195255 },
{ "date": new Date('2026-06-26T00:00:00.000Z'), "open": 174.18, "high": 176.23, "low": 170.05, "close": 172.55, "volume": 1956910 },
{ "date": new Date('2026-06-27T00:00:00.000Z'), "open": 172.55, "high": 177.03, "low": 172.1, "close": 175.33, "volume": 2294555 },
{ "date": new Date('2026-06-28T00:00:00.000Z'), "open": 175.33, "high": 180.25, "low": 174.18, "close": 178.33, "volume": 3702584 },
{ "date": new Date('2026-06-29T00:00:00.000Z'), "open": 178.33, "high": 178.83, "low": 175.83, "close": 176.69, "volume": 2561676 },
{ "date": new Date('2026-06-30T00:00:00.000Z'), "open": 176.69, "high": 178.45, "low": 175.77, "close": 176.71, "volume": 1691710 },
{ "date": new Date('2026-07-01T00:00:00.000Z'), "open": 176.71, "high": 177.68, "low": 174.58, "close": 175.69, "volume": 1891064 },
{ "date": new Date('2026-07-02T00:00:00.000Z'), "open": 175.69, "high": 176.87, "low": 172.86, "close": 175.31, "volume": 1862025 },
{ "date": new Date('2026-07-03T00:00:00.000Z'), "open": 175.31, "high": 178.66, "low": 173.7, "close": 178.41, "volume": 2873801 },
{ "date": new Date('2026-07-04T00:00:00.000Z'), "open": 178.41, "high": 181.32, "low": 176.93, "close": 179.67, "volume": 2917261 },
{ "date": new Date('2026-07-05T00:00:00.000Z'), "open": 179.67, "high": 182.32, "low": 176.74, "close": 178.41, "volume": 1924836 },
{ "date": new Date('2026-07-06T00:00:00.000Z'), "open": 178.41, "high": 182.22, "low": 175.89, "close": 181.04, "volume": 2601632 },
{ "date": new Date('2026-07-07T00:00:00.000Z'), "open": 181.04, "high": 181.73, "low": 177.68, "close": 178.74, "volume": 2747583 },
{ "date": new Date('2026-07-08T00:00:00.000Z'), "open": 178.74, "high": 180.38, "low": 176.15, "close": 180.24, "volume": 1829364 },
{ "date": new Date('2026-07-09T00:00:00.000Z'), "open": 180.24, "high": 181.75, "low": 176.53, "close": 178.88, "volume": 2875169 },
{ "date": new Date('2026-07-10T00:00:00.000Z'), "open": 178.88, "high": 180.17, "low": 178.39, "close": 180.16, "volume": 1771891 },
{ "date": new Date('2026-07-11T00:00:00.000Z'), "open": 180.16, "high": 182.25, "low": 178.11, "close": 178.34, "volume": 1760700 },
{ "date": new Date('2026-07-12T00:00:00.000Z'), "open": 178.34, "high": 183.67, "low": 175.68, "close": 181.53, "volume": 2986133 },
{ "date": new Date('2026-07-13T00:00:00.000Z'), "open": 181.53, "high": 183.06, "low": 178.25, "close": 180.7, "volume": 2754332 },
{ "date": new Date('2026-07-14T00:00:00.000Z'), "open": 180.7, "high": 182.04, "low": 178.8, "close": 181.02, "volume": 2853710 },
{ "date": new Date('2026-07-15T00:00:00.000Z'), "open": 181.02, "high": 184.6, "low": 178.5, "close": 182.81, "volume": 3309967 },
{ "date": new Date('2026-07-16T00:00:00.000Z'), "open": 182.81, "high": 187.85, "low": 180.39, "close": 185.86, "volume": 2219317 },
{ "date": new Date('2026-07-17T00:00:00.000Z'), "open": 185.86, "high": 186.1, "low": 181.67, "close": 184.07, "volume": 2014204 },
{ "date": new Date('2026-07-18T00:00:00.000Z'), "open": 184.07, "high": 185.04, "low": 180.87, "close": 182.15, "volume": 2597964 },
{ "date": new Date('2026-07-19T00:00:00.000Z'), "open": 182.15, "high": 185.62, "low": 181.28, "close": 182.95, "volume": 1855149 },
{ "date": new Date('2026-07-20T00:00:00.000Z'), "open": 182.95, "high": 184.31, "low": 179.38, "close": 180.08, "volume": 3538359 },
{ "date": new Date('2026-07-21T00:00:00.000Z'), "open": 180.08, "high": 183.87, "low": 178.35, "close": 182.21, "volume": 2111130 },
{ "date": new Date('2026-07-22T00:00:00.000Z'), "open": 182.21, "high": 183.77, "low": 179.79, "close": 182.59, "volume": 2470964 },
{ "date": new Date('2026-07-23T00:00:00.000Z'), "open": 182.59, "high": 185.11, "low": 178.74, "close": 180, "volume": 2215306 },
{ "date": new Date('2026-07-24T00:00:00.000Z'), "open": 180, "high": 182.37, "low": 179.22, "close": 181.3, "volume": 1930100 },
{ "date": new Date('2026-07-25T00:00:00.000Z'), "open": 181.3, "high": 182.29, "low": 176.78, "close": 179.41, "volume": 2564712 },
{ "date": new Date('2026-07-26T00:00:00.000Z'), "open": 179.41, "high": 181.57, "low": 176.8, "close": 179.78, "volume": 2695389 },
{ "date": new Date('2026-07-27T00:00:00.000Z'), "open": 179.78, "high": 183.37, "low": 177.65, "close": 182.53, "volume": 2612169 },
{ "date": new Date('2026-07-28T00:00:00.000Z'), "open": 182.53, "high": 185.98, "low": 180.64, "close": 185.06, "volume": 2871046 },
{ "date": new Date('2026-07-29T00:00:00.000Z'), "open": 185.06, "high": 185.86, "low": 180.35, "close": 182.69, "volume": 1950375 },
{ "date": new Date('2026-07-30T00:00:00.000Z'), "open": 182.69, "high": 185.15, "low": 177.55, "close": 180.14, "volume": 3537483 },
{ "date": new Date('2026-07-31T00:00:00.000Z'), "open": 180.14, "high": 180.56, "low": 178.7, "close": 179.29, "volume": 3027806 },
{ "date": new Date('2026-08-01T00:00:00.000Z'), "open": 179.29, "high": 183.63, "low": 178.43, "close": 181.63, "volume": 2848629 },
{ "date": new Date('2026-08-02T00:00:00.000Z'), "open": 181.63, "high": 185.46, "low": 179.23, "close": 182.99, "volume": 2719123 },
{ "date": new Date('2026-08-03T00:00:00.000Z'), "open": 182.99, "high": 183.03, "low": 181.76, "close": 181.94, "volume": 2892428 },
{ "date": new Date('2026-08-04T00:00:00.000Z'), "open": 181.94, "high": 184.62, "low": 181.8, "close": 182.87, "volume": 3059787 },
{ "date": new Date('2026-08-05T00:00:00.000Z'), "open": 182.87, "high": 183.86, "low": 179.61, "close": 180.65, "volume": 3153744 },
{ "date": new Date('2026-08-06T00:00:00.000Z'), "open": 180.65, "high": 183.48, "low": 180.36, "close": 183.38, "volume": 2096144 },
{ "date": new Date('2026-08-07T00:00:00.000Z'), "open": 183.38, "high": 183.72, "low": 179.24, "close": 181.35, "volume": 2428129 },
{ "date": new Date('2026-08-08T00:00:00.000Z'), "open": 181.35, "high": 183.15, "low": 178.87, "close": 181.68, "volume": 1957201 },
{ "date": new Date('2026-08-09T00:00:00.000Z'), "open": 181.68, "high": 184.48, "low": 180.15, "close": 184.09, "volume": 3131278 },
{ "date": new Date('2026-08-10T00:00:00.000Z'), "open": 184.09, "high": 187.25, "low": 182.16, "close": 184.76, "volume": 1986018 },
{ "date": new Date('2026-08-11T00:00:00.000Z'), "open": 184.76, "high": 185.27, "low": 181.34, "close": 184.06, "volume": 2629438 },
{ "date": new Date('2026-08-12T00:00:00.000Z'), "open": 184.06, "high": 185.48, "low": 181.89, "close": 182.38, "volume": 2086285 },
{ "date": new Date('2026-08-13T00:00:00.000Z'), "open": 182.38, "high": 185.11, "low": 180.61, "close": 183.66, "volume": 2860446 },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "open": 183.66, "high": 184.63, "low": 180.29, "close": 181.67, "volume": 2398495 },
{ "date": new Date('2026-08-15T00:00:00.000Z'), "open": 181.67, "high": 185.05, "low": 179.28, "close": 184.46, "volume": 2448935 },
{ "date": new Date('2026-08-16T00:00:00.000Z'), "open": 184.46, "high": 187.8, "low": 182.88, "close": 186.13, "volume": 2425201 },
{ "date": new Date('2026-08-17T00:00:00.000Z'), "open": 186.13, "high": 188.94, "low": 184.01, "close": 184.01, "volume": 2897024 },
{ "date": new Date('2026-08-18T00:00:00.000Z'), "open": 184.01, "high": 185.14, "low": 181.96, "close": 185.05, "volume": 2346585 },
{ "date": new Date('2026-08-19T00:00:00.000Z'), "open": 185.05, "high": 187.56, "low": 181.6, "close": 183.2, "volume": 1782162 },
{ "date": new Date('2026-08-20T00:00:00.000Z'), "open": 183.2, "high": 183.37, "low": 181.1, "close": 182.24, "volume": 3222334 },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "open": 182.24, "high": 187.12, "low": 180.33, "close": 184.51, "volume": 2058942 },
{ "date": new Date('2026-08-22T00:00:00.000Z'), "open": 184.51, "high": 187.36, "low": 184.49, "close": 186.44, "volume": 1849602 },
{ "date": new Date('2026-08-23T00:00:00.000Z'), "open": 186.44, "high": 189.61, "low": 183.73, "close": 188.9, "volume": 1968815 },
{ "date": new Date('2026-08-24T00:00:00.000Z'), "open": 188.9, "high": 192.67, "low": 188.31, "close": 191.85, "volume": 3047593 },
{ "date": new Date('2026-08-25T00:00:00.000Z'), "open": 191.85, "high": 194.69, "low": 188.25, "close": 190.53, "volume": 1890866 },
{ "date": new Date('2026-08-26T00:00:00.000Z'), "open": 190.53, "high": 192.03, "low": 188.23, "close": 190.78, "volume": 1826419 },
{ "date": new Date('2026-08-27T00:00:00.000Z'), "open": 190.78, "high": 196.36, "low": 190.07, "close": 193.85, "volume": 2686171 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "open": 193.85, "high": 197.11, "low": 192.05, "close": 194.2, "volume": 2566984 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "open": 194.2, "high": 194.38, "low": 191.92, "close": 192.45, "volume": 2585676 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "open": 192.45, "high": 192.6, "low": 190.83, "close": 191.48, "volume": 2902453 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "open": 191.48, "high": 195.18, "low": 190.07, "close": 194.15, "volume": 2226035 },
{ "date": new Date('2026-09-01T00:00:00.000Z'), "open": 194.15, "high": 194.96, "low": 191.2, "close": 194.68, "volume": 2865378 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "open": 194.68, "high": 195.97, "low": 191.95, "close": 192.18, "volume": 3179562 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "open": 192.18, "high": 197.54, "low": 190.1, "close": 195.29, "volume": 2203328 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "open": 195.29, "high": 200.11, "low": 193.34, "close": 197.72, "volume": 3287887 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "open": 197.72, "high": 202.47, "low": 196.55, "close": 200.86, "volume": 2108982 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "open": 200.86, "high": 202.44, "low": 200.14, "close": 201.7, "volume": 3050788 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "open": 201.7, "high": 206.09, "low": 201.08, "close": 203.76, "volume": 3160303 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "open": 203.76, "high": 205.09, "low": 203.28, "close": 203.62, "volume": 1547552 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "open": 203.62, "high": 206.45, "low": 199.93, "close": 200.54, "volume": 2419421 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "open": 200.54, "high": 203.41, "low": 196.4, "close": 199.31, "volume": 2137922 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "open": 199.31, "high": 201.44, "low": 197.01, "close": 197.94, "volume": 2856143 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "open": 197.94, "high": 200.87, "low": 193.01, "close": 195.54, "volume": 2016849 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "open": 195.54, "high": 197.51, "low": 192.95, "close": 196.79, "volume": 2621817 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "open": 196.79, "high": 199.2, "low": 194.82, "close": 197.52, "volume": 3033046 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "open": 197.52, "high": 203.69, "low": 197, "close": 200.66, "volume": 3041051 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "open": 200.66, "high": 204.11, "low": 198.61, "close": 203.59, "volume": 2082501 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "open": 203.59, "high": 208.28, "low": 201.87, "close": 205.27, "volume": 3222974 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "open": 205.27, "high": 206.64, "low": 203, "close": 203.49, "volume": 2462821 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "open": 203.49, "high": 204.33, "low": 198.71, "close": 200.51, "volume": 2368043 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "open": 200.51, "high": 204.21, "low": 199.53, "close": 204.04, "volume": 2964809 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "open": 204.04, "high": 205.6, "low": 199.82, "close": 201.65, "volume": 3263425 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "open": 201.65, "high": 206.26, "low": 198.81, "close": 203.2, "volume": 3180001 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "open": 203.2, "high": 206.48, "low": 200.12, "close": 205.46, "volume": 2041039 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "open": 205.46, "high": 208.24, "low": 202.34, "close": 203.24, "volume": 2468141 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "open": 203.24, "high": 206, "low": 202.82, "close": 205.56, "volume": 2886985 },
] },
];
export function Example() {
return (
);
}
```
#### Six years on a log scale
Six years of weekly candles on a log axis, so early moves stay as readable as recent ones.
```tsx
'use client';
import { CandlestickChartCard } from '@lilt-ui/charts/finance';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This period", "data": [
{ "date": new Date('2020-10-09T00:00:00.000Z'), "open": 3900, "high": 3910.79, "low": 3696.96, "close": 3794.1, "volume": 22547 },
{ "date": new Date('2020-10-16T00:00:00.000Z'), "open": 3794.1, "high": 3827.02, "low": 3691.98, "close": 3770.16, "volume": 23957 },
{ "date": new Date('2020-10-23T00:00:00.000Z'), "open": 3770.16, "high": 3918.29, "low": 3661.95, "close": 3916.87, "volume": 25138 },
{ "date": new Date('2020-10-30T00:00:00.000Z'), "open": 3916.87, "high": 4073.2, "low": 3679.15, "close": 3808.63, "volume": 24804 },
{ "date": new Date('2020-11-06T00:00:00.000Z'), "open": 3808.63, "high": 3936.85, "low": 3738.85, "close": 3928.05, "volume": 28314 },
{ "date": new Date('2020-11-13T00:00:00.000Z'), "open": 3928.05, "high": 4173.37, "low": 3793.47, "close": 4137.68, "volume": 30092 },
{ "date": new Date('2020-11-20T00:00:00.000Z'), "open": 4137.68, "high": 4268.91, "low": 4036.78, "close": 4062.64, "volume": 24788 },
{ "date": new Date('2020-11-27T00:00:00.000Z'), "open": 4062.64, "high": 4146.34, "low": 3899.73, "close": 4055.09, "volume": 20142 },
{ "date": new Date('2020-12-04T00:00:00.000Z'), "open": 4055.09, "high": 4395.45, "low": 3949.04, "close": 4238.71, "volume": 34797 },
{ "date": new Date('2020-12-11T00:00:00.000Z'), "open": 4238.71, "high": 4398.04, "low": 4185.35, "close": 4359.68, "volume": 25664 },
{ "date": new Date('2020-12-18T00:00:00.000Z'), "open": 4359.68, "high": 4733.23, "low": 4216.7, "close": 4557.54, "volume": 32735 },
{ "date": new Date('2020-12-25T00:00:00.000Z'), "open": 4557.54, "high": 4725, "low": 4490.27, "close": 4527.62, "volume": 16995 },
{ "date": new Date('2021-01-01T00:00:00.000Z'), "open": 4527.62, "high": 4725.85, "low": 4402.93, "close": 4695.2, "volume": 33185 },
{ "date": new Date('2021-01-08T00:00:00.000Z'), "open": 4695.2, "high": 4858.71, "low": 4584.51, "close": 4857.73, "volume": 27795 },
{ "date": new Date('2021-01-15T00:00:00.000Z'), "open": 4857.73, "high": 5088.76, "low": 4800.16, "close": 5015.23, "volume": 21068 },
{ "date": new Date('2021-01-22T00:00:00.000Z'), "open": 5015.23, "high": 5056.25, "low": 4716.62, "close": 4843.7, "volume": 22055 },
{ "date": new Date('2021-01-29T00:00:00.000Z'), "open": 4843.7, "high": 5110.89, "low": 4707.42, "close": 4923.96, "volume": 17578 },
{ "date": new Date('2021-02-05T00:00:00.000Z'), "open": 4923.96, "high": 5069.9, "low": 4719.48, "close": 4827.29, "volume": 20131 },
{ "date": new Date('2021-02-12T00:00:00.000Z'), "open": 4827.29, "high": 4989.66, "low": 4548.56, "close": 4687.56, "volume": 29852 },
{ "date": new Date('2021-02-19T00:00:00.000Z'), "open": 4687.56, "high": 4825.12, "low": 4655.97, "close": 4820.58, "volume": 27443 },
{ "date": new Date('2021-02-26T00:00:00.000Z'), "open": 4820.58, "high": 4967.87, "low": 4739.57, "close": 4924.28, "volume": 19894 },
{ "date": new Date('2021-03-05T00:00:00.000Z'), "open": 4924.28, "high": 5035.12, "low": 4659.75, "close": 4855.37, "volume": 14721 },
{ "date": new Date('2021-03-12T00:00:00.000Z'), "open": 4855.37, "high": 5091.59, "low": 4833.45, "close": 4992.24, "volume": 31195 },
{ "date": new Date('2021-03-19T00:00:00.000Z'), "open": 4992.24, "high": 5216.17, "low": 4794.54, "close": 5076.38, "volume": 25352 },
{ "date": new Date('2021-03-26T00:00:00.000Z'), "open": 5076.38, "high": 5322.78, "low": 5063.58, "close": 5282.42, "volume": 32931 },
{ "date": new Date('2021-04-02T00:00:00.000Z'), "open": 5282.42, "high": 5519.15, "low": 5132.21, "close": 5390.83, "volume": 25441 },
{ "date": new Date('2021-04-09T00:00:00.000Z'), "open": 5390.83, "high": 5622.03, "low": 5342.02, "close": 5489.93, "volume": 25183 },
{ "date": new Date('2021-04-16T00:00:00.000Z'), "open": 5489.93, "high": 5706.06, "low": 5239.96, "close": 5397.06, "volume": 16502 },
{ "date": new Date('2021-04-23T00:00:00.000Z'), "open": 5397.06, "high": 5598.89, "low": 5242.25, "close": 5275.94, "volume": 22724 },
{ "date": new Date('2021-04-30T00:00:00.000Z'), "open": 5275.94, "high": 5333.42, "low": 5116.07, "close": 5118.48, "volume": 30046 },
{ "date": new Date('2021-05-07T00:00:00.000Z'), "open": 5118.48, "high": 5243.93, "low": 4997.17, "close": 5190.37, "volume": 25941 },
{ "date": new Date('2021-05-14T00:00:00.000Z'), "open": 5190.37, "high": 5240.2, "low": 4964.43, "close": 5074.19, "volume": 18186 },
{ "date": new Date('2021-05-21T00:00:00.000Z'), "open": 5074.19, "high": 5220.5, "low": 4950.5, "close": 5118.28, "volume": 18407 },
{ "date": new Date('2021-05-28T00:00:00.000Z'), "open": 5118.28, "high": 5141.83, "low": 4817.96, "close": 4943.88, "volume": 26133 },
{ "date": new Date('2021-06-04T00:00:00.000Z'), "open": 4943.88, "high": 5086.71, "low": 4920.35, "close": 4988.26, "volume": 23128 },
{ "date": new Date('2021-06-11T00:00:00.000Z'), "open": 4988.26, "high": 5272.28, "low": 4828.92, "close": 5220.28, "volume": 31772 },
{ "date": new Date('2021-06-18T00:00:00.000Z'), "open": 5220.28, "high": 5273.89, "low": 5106.77, "close": 5203.98, "volume": 16738 },
{ "date": new Date('2021-06-25T00:00:00.000Z'), "open": 5203.98, "high": 5308.52, "low": 5178.2, "close": 5268.86, "volume": 15842 },
{ "date": new Date('2021-07-02T00:00:00.000Z'), "open": 5268.86, "high": 5537.11, "low": 5114.66, "close": 5471.52, "volume": 32215 },
{ "date": new Date('2021-07-09T00:00:00.000Z'), "open": 5471.52, "high": 5682.46, "low": 5331.62, "close": 5653.72, "volume": 31245 },
{ "date": new Date('2021-07-16T00:00:00.000Z'), "open": 5653.72, "high": 6019.65, "low": 5627.51, "close": 5788.02, "volume": 26683 },
{ "date": new Date('2021-07-23T00:00:00.000Z'), "open": 5788.02, "high": 5972.26, "low": 5482.19, "close": 5667.38, "volume": 20557 },
{ "date": new Date('2021-07-30T00:00:00.000Z'), "open": 5667.38, "high": 5877.99, "low": 5514.34, "close": 5735.08, "volume": 25026 },
{ "date": new Date('2021-08-06T00:00:00.000Z'), "open": 5735.08, "high": 5737.63, "low": 5654.87, "close": 5677.98, "volume": 23768 },
{ "date": new Date('2021-08-13T00:00:00.000Z'), "open": 5677.98, "high": 6052.96, "low": 5634.37, "close": 5827.71, "volume": 20514 },
{ "date": new Date('2021-08-20T00:00:00.000Z'), "open": 5827.71, "high": 6135.47, "low": 5797.55, "close": 6069.83, "volume": 25816 },
{ "date": new Date('2021-08-27T00:00:00.000Z'), "open": 6069.83, "high": 6182.5, "low": 5847.64, "close": 6177.47, "volume": 19166 },
{ "date": new Date('2021-09-03T00:00:00.000Z'), "open": 6177.47, "high": 6579.46, "low": 6159.73, "close": 6476.99, "volume": 28546 },
{ "date": new Date('2021-09-10T00:00:00.000Z'), "open": 6476.99, "high": 6922.58, "low": 6439.04, "close": 6754.2, "volume": 29290 },
{ "date": new Date('2021-09-17T00:00:00.000Z'), "open": 6754.2, "high": 6875.27, "low": 6644.94, "close": 6785.52, "volume": 21654 },
{ "date": new Date('2021-09-24T00:00:00.000Z'), "open": 6785.52, "high": 6916.3, "low": 6647.66, "close": 6753.05, "volume": 21865 },
{ "date": new Date('2021-10-01T00:00:00.000Z'), "open": 6753.05, "high": 6882.4, "low": 6518.02, "close": 6791.56, "volume": 14647 },
{ "date": new Date('2021-10-08T00:00:00.000Z'), "open": 6791.56, "high": 6936.98, "low": 6564.62, "close": 6901.22, "volume": 18892 },
{ "date": new Date('2021-10-15T00:00:00.000Z'), "open": 6901.22, "high": 7301.2, "low": 6798.4, "close": 7247.53, "volume": 26278 },
{ "date": new Date('2021-10-22T00:00:00.000Z'), "open": 7247.53, "high": 7728.91, "low": 7056.25, "close": 7613.37, "volume": 34073 },
{ "date": new Date('2021-10-29T00:00:00.000Z'), "open": 7613.37, "high": 8056.81, "low": 7340.01, "close": 7989.16, "volume": 31014 },
{ "date": new Date('2021-11-05T00:00:00.000Z'), "open": 7989.16, "high": 8116.1, "low": 7648.14, "close": 7746.6, "volume": 20371 },
{ "date": new Date('2021-11-12T00:00:00.000Z'), "open": 7746.6, "high": 7805.24, "low": 7326.15, "close": 7485.09, "volume": 30664 },
{ "date": new Date('2021-11-19T00:00:00.000Z'), "open": 7485.09, "high": 7912.42, "low": 7242.4, "close": 7853.6, "volume": 37820 },
{ "date": new Date('2021-11-26T00:00:00.000Z'), "open": 7853.6, "high": 8024.36, "low": 7574.7, "close": 7869.67, "volume": 20476 },
{ "date": new Date('2021-12-03T00:00:00.000Z'), "open": 7869.67, "high": 8184.48, "low": 7813.15, "close": 8108.23, "volume": 29571 },
{ "date": new Date('2021-12-10T00:00:00.000Z'), "open": 8108.23, "high": 8455.62, "low": 8075.54, "close": 8266.04, "volume": 22432 },
{ "date": new Date('2021-12-17T00:00:00.000Z'), "open": 8266.04, "high": 8525.71, "low": 8183.89, "close": 8343.28, "volume": 17238 },
{ "date": new Date('2021-12-24T00:00:00.000Z'), "open": 8343.28, "high": 8636.81, "low": 8159.78, "close": 8437.75, "volume": 24778 },
{ "date": new Date('2021-12-31T00:00:00.000Z'), "open": 8437.75, "high": 9038.16, "low": 8429.11, "close": 8723.43, "volume": 29335 },
{ "date": new Date('2022-01-07T00:00:00.000Z'), "open": 8723.43, "high": 8833.16, "low": 8462.78, "close": 8640.63, "volume": 13183 },
{ "date": new Date('2022-01-14T00:00:00.000Z'), "open": 8640.63, "high": 9051.88, "low": 8466.39, "close": 8767.1, "volume": 17341 },
{ "date": new Date('2022-01-21T00:00:00.000Z'), "open": 8767.1, "high": 9108.26, "low": 8764.59, "close": 8958.38, "volume": 20849 },
{ "date": new Date('2022-01-28T00:00:00.000Z'), "open": 8958.38, "high": 9008, "low": 8784.92, "close": 8972.56, "volume": 13521 },
{ "date": new Date('2022-02-04T00:00:00.000Z'), "open": 8972.56, "high": 9324.9, "low": 8500.97, "close": 8769.78, "volume": 19096 },
{ "date": new Date('2022-02-11T00:00:00.000Z'), "open": 8769.78, "high": 9157.43, "low": 8722.22, "close": 8868.17, "volume": 20254 },
{ "date": new Date('2022-02-18T00:00:00.000Z'), "open": 8868.17, "high": 9112.53, "low": 8551.63, "close": 9013.75, "volume": 19272 },
{ "date": new Date('2022-02-25T00:00:00.000Z'), "open": 9013.75, "high": 9038.02, "low": 8837.42, "close": 8921.82, "volume": 24220 },
{ "date": new Date('2022-03-04T00:00:00.000Z'), "open": 8921.82, "high": 9253.96, "low": 8800.59, "close": 9061.34, "volume": 26419 },
{ "date": new Date('2022-03-11T00:00:00.000Z'), "open": 9061.34, "high": 9554.53, "low": 8860.73, "close": 9282.88, "volume": 21766 },
{ "date": new Date('2022-03-18T00:00:00.000Z'), "open": 9282.88, "high": 9475.18, "low": 8968.91, "close": 8985.56, "volume": 25687 },
{ "date": new Date('2022-03-25T00:00:00.000Z'), "open": 8985.56, "high": 9323.16, "low": 8909.95, "close": 9272.91, "volume": 28062 },
{ "date": new Date('2022-04-01T00:00:00.000Z'), "open": 9272.91, "high": 9547.49, "low": 8891.85, "close": 8993.31, "volume": 28430 },
{ "date": new Date('2022-04-08T00:00:00.000Z'), "open": 8993.31, "high": 9059.96, "low": 8700.86, "close": 8944.52, "volume": 15762 },
{ "date": new Date('2022-04-15T00:00:00.000Z'), "open": 8944.52, "high": 9277.89, "low": 8834, "close": 8868.2, "volume": 15955 },
{ "date": new Date('2022-04-22T00:00:00.000Z'), "open": 8868.2, "high": 9438.72, "low": 8655.85, "close": 9073.49, "volume": 18314 },
{ "date": new Date('2022-04-29T00:00:00.000Z'), "open": 9073.49, "high": 9561.33, "low": 8888.03, "close": 9520.81, "volume": 31232 },
{ "date": new Date('2022-05-06T00:00:00.000Z'), "open": 9520.81, "high": 9591.15, "low": 9386.14, "close": 9514.08, "volume": 22647 },
{ "date": new Date('2022-05-13T00:00:00.000Z'), "open": 9514.08, "high": 9936.37, "low": 9137.23, "close": 9662.86, "volume": 26988 },
{ "date": new Date('2022-05-20T00:00:00.000Z'), "open": 9662.86, "high": 9794.94, "low": 9155.32, "close": 9422.62, "volume": 27993 },
{ "date": new Date('2022-05-27T00:00:00.000Z'), "open": 9422.62, "high": 9582.59, "low": 9072.05, "close": 9360.75, "volume": 16529 },
{ "date": new Date('2022-06-03T00:00:00.000Z'), "open": 9360.75, "high": 9464.56, "low": 8952.81, "close": 9217.98, "volume": 22818 },
{ "date": new Date('2022-06-10T00:00:00.000Z'), "open": 9217.98, "high": 9785.4, "low": 9149.35, "close": 9597.98, "volume": 28694 },
{ "date": new Date('2022-06-17T00:00:00.000Z'), "open": 9597.98, "high": 9830.67, "low": 9303.42, "close": 9495.3, "volume": 20220 },
{ "date": new Date('2022-06-24T00:00:00.000Z'), "open": 9495.3, "high": 10108.34, "low": 9423.2, "close": 9819.45, "volume": 29881 },
{ "date": new Date('2022-07-01T00:00:00.000Z'), "open": 9819.45, "high": 10165, "low": 9558.26, "close": 9798.95, "volume": 18180 },
{ "date": new Date('2022-07-08T00:00:00.000Z'), "open": 9798.95, "high": 10043.04, "low": 9573.07, "close": 9693.26, "volume": 20999 },
{ "date": new Date('2022-07-15T00:00:00.000Z'), "open": 9693.26, "high": 10342.27, "low": 9339.18, "close": 10078.33, "volume": 28603 },
{ "date": new Date('2022-07-22T00:00:00.000Z'), "open": 10078.33, "high": 10213.43, "low": 9733.68, "close": 9755.81, "volume": 22573 },
{ "date": new Date('2022-07-29T00:00:00.000Z'), "open": 9755.81, "high": 9970.62, "low": 9687.7, "close": 9744.14, "volume": 22019 },
{ "date": new Date('2022-08-05T00:00:00.000Z'), "open": 9744.14, "high": 10288.86, "low": 9633.93, "close": 10103.38, "volume": 26783 },
{ "date": new Date('2022-08-12T00:00:00.000Z'), "open": 10103.38, "high": 10667.23, "low": 9730.25, "close": 10493.3, "volume": 22636 },
{ "date": new Date('2022-08-19T00:00:00.000Z'), "open": 10493.3, "high": 10935.38, "low": 10387.69, "close": 10850.79, "volume": 25061 },
{ "date": new Date('2022-08-26T00:00:00.000Z'), "open": 10850.79, "high": 11071.12, "low": 10405.1, "close": 10832.13, "volume": 16794 },
{ "date": new Date('2022-09-02T00:00:00.000Z'), "open": 10832.13, "high": 11594.21, "low": 10815.92, "close": 11402.48, "volume": 35714 },
{ "date": new Date('2022-09-09T00:00:00.000Z'), "open": 11402.48, "high": 12213.63, "low": 10973.59, "close": 11957.03, "volume": 33551 },
{ "date": new Date('2022-09-16T00:00:00.000Z'), "open": 11957.03, "high": 13019.51, "low": 11695.31, "close": 12533.57, "volume": 37429 },
{ "date": new Date('2022-09-23T00:00:00.000Z'), "open": 12533.57, "high": 12627.99, "low": 11949.21, "close": 12215.99, "volume": 26005 },
{ "date": new Date('2022-09-30T00:00:00.000Z'), "open": 12215.99, "high": 12431.37, "low": 11702.51, "close": 12024.61, "volume": 26076 },
{ "date": new Date('2022-10-07T00:00:00.000Z'), "open": 12024.61, "high": 12773.23, "low": 11617.46, "close": 12642.78, "volume": 33161 },
{ "date": new Date('2022-10-14T00:00:00.000Z'), "open": 12642.78, "high": 12895.82, "low": 12178.59, "close": 12827.11, "volume": 17382 },
{ "date": new Date('2022-10-21T00:00:00.000Z'), "open": 12827.11, "high": 13690.78, "low": 12476.9, "close": 13220.74, "volume": 25076 },
{ "date": new Date('2022-10-28T00:00:00.000Z'), "open": 13220.74, "high": 14284.85, "low": 13086.82, "close": 13903.67, "volume": 37281 },
{ "date": new Date('2022-11-04T00:00:00.000Z'), "open": 13903.67, "high": 14057.62, "low": 13174.67, "close": 13429.18, "volume": 21805 },
{ "date": new Date('2022-11-11T00:00:00.000Z'), "open": 13429.18, "high": 14135.35, "low": 13285, "close": 14016.32, "volume": 36308 },
{ "date": new Date('2022-11-18T00:00:00.000Z'), "open": 14016.32, "high": 14247.91, "low": 13702.65, "close": 14007.87, "volume": 10743 },
{ "date": new Date('2022-11-25T00:00:00.000Z'), "open": 14007.87, "high": 14826.18, "low": 13993.39, "close": 14674.49, "volume": 37222 },
{ "date": new Date('2022-12-02T00:00:00.000Z'), "open": 14674.49, "high": 15265.51, "low": 14206.21, "close": 14303.15, "volume": 26454 },
{ "date": new Date('2022-12-09T00:00:00.000Z'), "open": 14303.15, "high": 14466.81, "low": 14211.17, "close": 14377.65, "volume": 23920 },
{ "date": new Date('2022-12-16T00:00:00.000Z'), "open": 14377.65, "high": 14447.31, "low": 14155.9, "close": 14156.83, "volume": 15713 },
{ "date": new Date('2022-12-23T00:00:00.000Z'), "open": 14156.83, "high": 14866.67, "low": 13606.57, "close": 14432.47, "volume": 17228 },
{ "date": new Date('2022-12-30T00:00:00.000Z'), "open": 14432.47, "high": 15593.17, "low": 14154.18, "close": 15137.3, "volume": 27906 },
{ "date": new Date('2023-01-06T00:00:00.000Z'), "open": 15137.3, "high": 16176.89, "low": 14601.94, "close": 15954.19, "volume": 37386 },
{ "date": new Date('2023-01-13T00:00:00.000Z'), "open": 15954.19, "high": 17037.32, "low": 15467.61, "close": 16410.92, "volume": 19293 },
{ "date": new Date('2023-01-20T00:00:00.000Z'), "open": 16410.92, "high": 16950.36, "low": 16125.09, "close": 16504.37, "volume": 20464 },
{ "date": new Date('2023-01-27T00:00:00.000Z'), "open": 16504.37, "high": 16761.5, "low": 15979.59, "close": 16293.24, "volume": 19363 },
{ "date": new Date('2023-02-03T00:00:00.000Z'), "open": 16293.24, "high": 17080.84, "low": 16217.52, "close": 17012.97, "volume": 36356 },
{ "date": new Date('2023-02-10T00:00:00.000Z'), "open": 17012.97, "high": 17716.01, "low": 16441.2, "close": 17386.07, "volume": 21492 },
{ "date": new Date('2023-02-17T00:00:00.000Z'), "open": 17386.07, "high": 17691.48, "low": 17378.5, "close": 17680.94, "volume": 20471 },
{ "date": new Date('2023-02-24T00:00:00.000Z'), "open": 17680.94, "high": 18227.49, "low": 17216.42, "close": 18150.85, "volume": 25056 },
{ "date": new Date('2023-03-03T00:00:00.000Z'), "open": 18150.85, "high": 18548.13, "low": 18034.31, "close": 18116.12, "volume": 11689 },
{ "date": new Date('2023-03-10T00:00:00.000Z'), "open": 18116.12, "high": 19064.33, "low": 17674.77, "close": 18610.1, "volume": 23332 },
{ "date": new Date('2023-03-17T00:00:00.000Z'), "open": 18610.1, "high": 19125.47, "low": 17768.87, "close": 18101.33, "volume": 21449 },
{ "date": new Date('2023-03-24T00:00:00.000Z'), "open": 18101.33, "high": 18913.19, "low": 17850.07, "close": 18896.31, "volume": 30128 },
{ "date": new Date('2023-03-31T00:00:00.000Z'), "open": 18896.31, "high": 19206.81, "low": 17870.37, "close": 18294.23, "volume": 31480 },
{ "date": new Date('2023-04-07T00:00:00.000Z'), "open": 18294.23, "high": 18418.09, "low": 17210.66, "close": 17799.74, "volume": 29940 },
{ "date": new Date('2023-04-14T00:00:00.000Z'), "open": 17799.74, "high": 17831.62, "low": 16859.37, "close": 17271.96, "volume": 31529 },
{ "date": new Date('2023-04-21T00:00:00.000Z'), "open": 17271.96, "high": 18583.02, "low": 17117.52, "close": 18216.71, "volume": 36155 },
{ "date": new Date('2023-04-28T00:00:00.000Z'), "open": 18216.71, "high": 18901.54, "low": 17165.83, "close": 17856.58, "volume": 24230 },
{ "date": new Date('2023-05-05T00:00:00.000Z'), "open": 17856.58, "high": 18480.64, "low": 16815.39, "close": 17238.34, "volume": 31039 },
{ "date": new Date('2023-05-12T00:00:00.000Z'), "open": 17238.34, "high": 17451.84, "low": 16240.93, "close": 16642.25, "volume": 26261 },
{ "date": new Date('2023-05-19T00:00:00.000Z'), "open": 16642.25, "high": 17659.88, "low": 16367.04, "close": 17215.98, "volume": 22848 },
{ "date": new Date('2023-05-26T00:00:00.000Z'), "open": 17215.98, "high": 18215.23, "low": 17150.67, "close": 18055.65, "volume": 27813 },
{ "date": new Date('2023-06-02T00:00:00.000Z'), "open": 18055.65, "high": 18089.74, "low": 17006.39, "close": 17611.4, "volume": 21363 },
{ "date": new Date('2023-06-09T00:00:00.000Z'), "open": 17611.4, "high": 18291.72, "low": 17285.1, "close": 17491.8, "volume": 23608 },
{ "date": new Date('2023-06-16T00:00:00.000Z'), "open": 17491.8, "high": 18529.75, "low": 17335.13, "close": 18051.39, "volume": 23451 },
{ "date": new Date('2023-06-23T00:00:00.000Z'), "open": 18051.39, "high": 18771.23, "low": 17794.63, "close": 18092.31, "volume": 21410 },
{ "date": new Date('2023-06-30T00:00:00.000Z'), "open": 18092.31, "high": 18451.74, "low": 17719.09, "close": 18329.07, "volume": 14405 },
{ "date": new Date('2023-07-07T00:00:00.000Z'), "open": 18329.07, "high": 18523.71, "low": 17514.31, "close": 18071.39, "volume": 16238 },
{ "date": new Date('2023-07-14T00:00:00.000Z'), "open": 18071.39, "high": 19145.22, "low": 17401.23, "close": 18825.58, "volume": 30441 },
{ "date": new Date('2023-07-21T00:00:00.000Z'), "open": 18825.58, "high": 19536.67, "low": 17806.46, "close": 18450.8, "volume": 16377 },
{ "date": new Date('2023-07-28T00:00:00.000Z'), "open": 18450.8, "high": 18745.68, "low": 18179.81, "close": 18347.95, "volume": 15603 },
{ "date": new Date('2023-08-04T00:00:00.000Z'), "open": 18347.95, "high": 19123.54, "low": 18322.59, "close": 18845.62, "volume": 24606 },
{ "date": new Date('2023-08-11T00:00:00.000Z'), "open": 18845.62, "high": 19624.33, "low": 18504.43, "close": 19279.98, "volume": 18993 },
{ "date": new Date('2023-08-18T00:00:00.000Z'), "open": 19279.98, "high": 19716.83, "low": 18624.41, "close": 19098.07, "volume": 25479 },
{ "date": new Date('2023-08-25T00:00:00.000Z'), "open": 19098.07, "high": 19522, "low": 18071.13, "close": 18514.72, "volume": 26326 },
{ "date": new Date('2023-09-01T00:00:00.000Z'), "open": 18514.72, "high": 19081.1, "low": 17674.24, "close": 18013.49, "volume": 30520 },
{ "date": new Date('2023-09-08T00:00:00.000Z'), "open": 18013.49, "high": 19155.95, "low": 17634.44, "close": 18770.29, "volume": 28887 },
{ "date": new Date('2023-09-15T00:00:00.000Z'), "open": 18770.29, "high": 19353.94, "low": 17829.11, "close": 18501.39, "volume": 22687 },
{ "date": new Date('2023-09-22T00:00:00.000Z'), "open": 18501.39, "high": 19194.79, "low": 17740.44, "close": 18103.92, "volume": 19816 },
{ "date": new Date('2023-09-29T00:00:00.000Z'), "open": 18103.92, "high": 18292.67, "low": 17213.89, "close": 17734.98, "volume": 28278 },
{ "date": new Date('2023-10-06T00:00:00.000Z'), "open": 17734.98, "high": 18993.7, "low": 17294.99, "close": 18258.4, "volume": 27039 },
{ "date": new Date('2023-10-13T00:00:00.000Z'), "open": 18258.4, "high": 18686.3, "low": 18211.31, "close": 18579.65, "volume": 16395 },
{ "date": new Date('2023-10-20T00:00:00.000Z'), "open": 18579.65, "high": 20147.24, "low": 18537.67, "close": 19373.61, "volume": 26923 },
{ "date": new Date('2023-10-27T00:00:00.000Z'), "open": 19373.61, "high": 19721.57, "low": 18613.27, "close": 19006.16, "volume": 18899 },
{ "date": new Date('2023-11-03T00:00:00.000Z'), "open": 19006.16, "high": 19598.57, "low": 18180.04, "close": 18385.18, "volume": 27405 },
{ "date": new Date('2023-11-10T00:00:00.000Z'), "open": 18385.18, "high": 19084.37, "low": 18048.76, "close": 18449.85, "volume": 12345 },
{ "date": new Date('2023-11-17T00:00:00.000Z'), "open": 18449.85, "high": 19465.26, "low": 18335.43, "close": 18771.67, "volume": 24377 },
{ "date": new Date('2023-11-24T00:00:00.000Z'), "open": 18771.67, "high": 19590.4, "low": 18742.19, "close": 19498.46, "volume": 33349 },
{ "date": new Date('2023-12-01T00:00:00.000Z'), "open": 19498.46, "high": 20071.23, "low": 18445.03, "close": 19208.24, "volume": 17011 },
{ "date": new Date('2023-12-08T00:00:00.000Z'), "open": 19208.24, "high": 20880.13, "low": 18903.94, "close": 20222.01, "volume": 30502 },
{ "date": new Date('2023-12-15T00:00:00.000Z'), "open": 20222.01, "high": 20880.97, "low": 19691.94, "close": 19994.52, "volume": 26026 },
{ "date": new Date('2023-12-22T00:00:00.000Z'), "open": 19994.52, "high": 20018.38, "low": 19176.43, "close": 19573.92, "volume": 25190 },
{ "date": new Date('2023-12-29T00:00:00.000Z'), "open": 19573.92, "high": 20802.7, "low": 18868.07, "close": 20259.94, "volume": 31945 },
{ "date": new Date('2024-01-05T00:00:00.000Z'), "open": 20259.94, "high": 21147.99, "low": 19796.99, "close": 20372.13, "volume": 23488 },
{ "date": new Date('2024-01-12T00:00:00.000Z'), "open": 20372.13, "high": 20923.46, "low": 19570.5, "close": 20248.98, "volume": 17528 },
{ "date": new Date('2024-01-19T00:00:00.000Z'), "open": 20248.98, "high": 20375.11, "low": 20221.34, "close": 20334.84, "volume": 14351 },
{ "date": new Date('2024-01-26T00:00:00.000Z'), "open": 20334.84, "high": 21079.31, "low": 19864.05, "close": 20363.96, "volume": 19270 },
{ "date": new Date('2024-02-02T00:00:00.000Z'), "open": 20363.96, "high": 21062.28, "low": 19010.63, "close": 19723.31, "volume": 29309 },
{ "date": new Date('2024-02-09T00:00:00.000Z'), "open": 19723.31, "high": 19742.27, "low": 18355.26, "close": 19116.56, "volume": 30560 },
{ "date": new Date('2024-02-16T00:00:00.000Z'), "open": 19116.56, "high": 20461.9, "low": 19061.2, "close": 19910.31, "volume": 32986 },
{ "date": new Date('2024-02-23T00:00:00.000Z'), "open": 19910.31, "high": 20693.39, "low": 19158.89, "close": 20684.5, "volume": 34021 },
{ "date": new Date('2024-03-01T00:00:00.000Z'), "open": 20684.5, "high": 21301.61, "low": 19770.87, "close": 20538.27, "volume": 23024 },
{ "date": new Date('2024-03-08T00:00:00.000Z'), "open": 20538.27, "high": 22410.78, "low": 20174.56, "close": 21613.89, "volume": 27740 },
{ "date": new Date('2024-03-15T00:00:00.000Z'), "open": 21613.89, "high": 23173.3, "low": 20791.46, "close": 22610.57, "volume": 33455 },
{ "date": new Date('2024-03-22T00:00:00.000Z'), "open": 22610.57, "high": 23317.45, "low": 22446.19, "close": 23072.99, "volume": 17709 },
{ "date": new Date('2024-03-29T00:00:00.000Z'), "open": 23072.99, "high": 23992.03, "low": 21625.45, "close": 22395.63, "volume": 23289 },
{ "date": new Date('2024-04-05T00:00:00.000Z'), "open": 22395.63, "high": 23012.36, "low": 21811.67, "close": 21913.58, "volume": 29381 },
{ "date": new Date('2024-04-12T00:00:00.000Z'), "open": 21913.58, "high": 23491.98, "low": 21197.78, "close": 22826.91, "volume": 25640 },
{ "date": new Date('2024-04-19T00:00:00.000Z'), "open": 22826.91, "high": 23345.35, "low": 22170.63, "close": 22396.12, "volume": 26701 },
{ "date": new Date('2024-04-26T00:00:00.000Z'), "open": 22396.12, "high": 22535.41, "low": 21463.55, "close": 21787.27, "volume": 19362 },
{ "date": new Date('2024-05-03T00:00:00.000Z'), "open": 21787.27, "high": 22743.79, "low": 21607.57, "close": 22169.44, "volume": 27093 },
{ "date": new Date('2024-05-10T00:00:00.000Z'), "open": 22169.44, "high": 22974.47, "low": 21772.84, "close": 22164.16, "volume": 17895 },
{ "date": new Date('2024-05-17T00:00:00.000Z'), "open": 22164.16, "high": 23378.86, "low": 21420, "close": 23056.99, "volume": 27164 },
{ "date": new Date('2024-05-24T00:00:00.000Z'), "open": 23056.99, "high": 23688.68, "low": 23000.62, "close": 23359.24, "volume": 23465 },
{ "date": new Date('2024-05-31T00:00:00.000Z'), "open": 23359.24, "high": 23582.28, "low": 22663.4, "close": 23539.51, "volume": 16497 },
{ "date": new Date('2024-06-07T00:00:00.000Z'), "open": 23539.51, "high": 24285.2, "low": 23078.83, "close": 23727.83, "volume": 15609 },
{ "date": new Date('2024-06-14T00:00:00.000Z'), "open": 23727.83, "high": 24121.06, "low": 23579.4, "close": 23918.76, "volume": 22311 },
{ "date": new Date('2024-06-21T00:00:00.000Z'), "open": 23918.76, "high": 24682.94, "low": 23777.83, "close": 24219.92, "volume": 24709 },
{ "date": new Date('2024-06-28T00:00:00.000Z'), "open": 24219.92, "high": 24793.96, "low": 24089.02, "close": 24162.17, "volume": 21121 },
{ "date": new Date('2024-07-05T00:00:00.000Z'), "open": 24162.17, "high": 24960.39, "low": 23862.08, "close": 24571.15, "volume": 25028 },
{ "date": new Date('2024-07-12T00:00:00.000Z'), "open": 24571.15, "high": 25142.99, "low": 24111.06, "close": 24718.71, "volume": 13242 },
{ "date": new Date('2024-07-19T00:00:00.000Z'), "open": 24718.71, "high": 25777.43, "low": 24178.53, "close": 24780.19, "volume": 14809 },
{ "date": new Date('2024-07-26T00:00:00.000Z'), "open": 24780.19, "high": 25077.98, "low": 23752.28, "close": 24655.04, "volume": 16960 },
{ "date": new Date('2024-08-02T00:00:00.000Z'), "open": 24655.04, "high": 25680.56, "low": 23832.67, "close": 25608.66, "volume": 25770 },
{ "date": new Date('2024-08-09T00:00:00.000Z'), "open": 25608.66, "high": 27991.53, "low": 24702.35, "close": 26979.78, "volume": 34221 },
{ "date": new Date('2024-08-16T00:00:00.000Z'), "open": 26979.78, "high": 29484.73, "low": 26537.6, "close": 28400.89, "volume": 33017 },
{ "date": new Date('2024-08-23T00:00:00.000Z'), "open": 28400.89, "high": 29490.53, "low": 27604.59, "close": 29487.16, "volume": 33823 },
{ "date": new Date('2024-08-30T00:00:00.000Z'), "open": 29487.16, "high": 30737.27, "low": 29371.85, "close": 29620.97, "volume": 15739 },
{ "date": new Date('2024-09-06T00:00:00.000Z'), "open": 29620.97, "high": 29956.21, "low": 29058.02, "close": 29388.68, "volume": 23830 },
{ "date": new Date('2024-09-13T00:00:00.000Z'), "open": 29388.68, "high": 30352.56, "low": 28455.9, "close": 29396.38, "volume": 18037 },
{ "date": new Date('2024-09-20T00:00:00.000Z'), "open": 29396.38, "high": 29768.03, "low": 28813.17, "close": 29541.6, "volume": 18802 },
{ "date": new Date('2024-09-27T00:00:00.000Z'), "open": 29541.6, "high": 30765.25, "low": 28469.76, "close": 29708.99, "volume": 23288 },
{ "date": new Date('2024-10-04T00:00:00.000Z'), "open": 29708.99, "high": 32225.76, "low": 29337.22, "close": 31223.09, "volume": 30752 },
{ "date": new Date('2024-10-11T00:00:00.000Z'), "open": 31223.09, "high": 32569.11, "low": 30194.1, "close": 32417.95, "volume": 22722 },
{ "date": new Date('2024-10-18T00:00:00.000Z'), "open": 32417.95, "high": 35249.74, "low": 32200.96, "close": 34060.72, "volume": 29379 },
{ "date": new Date('2024-10-25T00:00:00.000Z'), "open": 34060.72, "high": 35194.76, "low": 33561.87, "close": 34289.78, "volume": 21864 },
{ "date": new Date('2024-11-01T00:00:00.000Z'), "open": 34289.78, "high": 35166.92, "low": 33626.88, "close": 34383.12, "volume": 15906 },
{ "date": new Date('2024-11-08T00:00:00.000Z'), "open": 34383.12, "high": 35074.34, "low": 32951.69, "close": 33580.01, "volume": 28293 },
{ "date": new Date('2024-11-15T00:00:00.000Z'), "open": 33580.01, "high": 34116.36, "low": 32428.91, "close": 33744.78, "volume": 14768 },
{ "date": new Date('2024-11-22T00:00:00.000Z'), "open": 33744.78, "high": 34163.13, "low": 33076.59, "close": 33443.09, "volume": 19181 },
{ "date": new Date('2024-11-29T00:00:00.000Z'), "open": 33443.09, "high": 33580.3, "low": 32903.77, "close": 33426.56, "volume": 18644 },
{ "date": new Date('2024-12-06T00:00:00.000Z'), "open": 33426.56, "high": 33578.57, "low": 32141.95, "close": 33144.5, "volume": 18643 },
{ "date": new Date('2024-12-13T00:00:00.000Z'), "open": 33144.5, "high": 33929.47, "low": 32480.34, "close": 32549.45, "volume": 22384 },
{ "date": new Date('2024-12-20T00:00:00.000Z'), "open": 32549.45, "high": 34964.58, "low": 32086.42, "close": 34192.29, "volume": 26694 },
{ "date": new Date('2024-12-27T00:00:00.000Z'), "open": 34192.29, "high": 35073.39, "low": 33277.97, "close": 34626.85, "volume": 19927 },
{ "date": new Date('2025-01-03T00:00:00.000Z'), "open": 34626.85, "high": 35339.46, "low": 34586.18, "close": 34779.3, "volume": 22528 },
{ "date": new Date('2025-01-10T00:00:00.000Z'), "open": 34779.3, "high": 35929.39, "low": 34606.73, "close": 35249.51, "volume": 26602 },
{ "date": new Date('2025-01-17T00:00:00.000Z'), "open": 35249.51, "high": 36594.89, "low": 33684.24, "close": 34039.4, "volume": 28833 },
{ "date": new Date('2025-01-24T00:00:00.000Z'), "open": 34039.4, "high": 36505.29, "low": 33936.46, "close": 35361.59, "volume": 31866 },
{ "date": new Date('2025-01-31T00:00:00.000Z'), "open": 35361.59, "high": 36173.54, "low": 33025.73, "close": 34363.04, "volume": 26482 },
{ "date": new Date('2025-02-07T00:00:00.000Z'), "open": 34363.04, "high": 35792.62, "low": 33011.59, "close": 35315.93, "volume": 30275 },
{ "date": new Date('2025-02-14T00:00:00.000Z'), "open": 35315.93, "high": 35516.25, "low": 33709.78, "close": 34874.71, "volume": 15417 },
{ "date": new Date('2025-02-21T00:00:00.000Z'), "open": 34874.71, "high": 35793.64, "low": 34623.99, "close": 35700.56, "volume": 25252 },
{ "date": new Date('2025-02-28T00:00:00.000Z'), "open": 35700.56, "high": 35782.12, "low": 33350.76, "close": 34627.11, "volume": 31057 },
{ "date": new Date('2025-03-07T00:00:00.000Z'), "open": 34627.11, "high": 34720.25, "low": 33222.03, "close": 33405.33, "volume": 26373 },
{ "date": new Date('2025-03-14T00:00:00.000Z'), "open": 33405.33, "high": 35839.34, "low": 32669.8, "close": 34579.92, "volume": 29848 },
{ "date": new Date('2025-03-21T00:00:00.000Z'), "open": 34579.92, "high": 36326.37, "low": 34015.21, "close": 35606.41, "volume": 27550 },
{ "date": new Date('2025-03-28T00:00:00.000Z'), "open": 35606.41, "high": 36290.11, "low": 34861.83, "close": 36031.56, "volume": 20845 },
{ "date": new Date('2025-04-04T00:00:00.000Z'), "open": 36031.56, "high": 37256.34, "low": 34709.29, "close": 34803.8, "volume": 26222 },
{ "date": new Date('2025-04-11T00:00:00.000Z'), "open": 34803.8, "high": 36469.21, "low": 34082.36, "close": 36243.32, "volume": 34607 },
{ "date": new Date('2025-04-18T00:00:00.000Z'), "open": 36243.32, "high": 37930.98, "low": 35295.89, "close": 37161.99, "volume": 24192 },
{ "date": new Date('2025-04-25T00:00:00.000Z'), "open": 37161.99, "high": 37385.47, "low": 35089.87, "close": 36443.48, "volume": 26005 },
{ "date": new Date('2025-05-02T00:00:00.000Z'), "open": 36443.48, "high": 36504.13, "low": 35511.55, "close": 36015.24, "volume": 19983 },
{ "date": new Date('2025-05-09T00:00:00.000Z'), "open": 36015.24, "high": 36394.93, "low": 34821.72, "close": 35539.83, "volume": 17960 },
{ "date": new Date('2025-05-16T00:00:00.000Z'), "open": 35539.83, "high": 36045.96, "low": 33878.06, "close": 34695.02, "volume": 22668 },
{ "date": new Date('2025-05-23T00:00:00.000Z'), "open": 34695.02, "high": 37447.26, "low": 33520.85, "close": 36027.08, "volume": 26759 },
{ "date": new Date('2025-05-30T00:00:00.000Z'), "open": 36027.08, "high": 37226.77, "low": 34703.64, "close": 36375.21, "volume": 15665 },
{ "date": new Date('2025-06-06T00:00:00.000Z'), "open": 36375.21, "high": 38452, "low": 35391.14, "close": 37548.23, "volume": 32193 },
{ "date": new Date('2025-06-13T00:00:00.000Z'), "open": 37548.23, "high": 37586.34, "low": 36542.05, "close": 36667.03, "volume": 27525 },
{ "date": new Date('2025-06-20T00:00:00.000Z'), "open": 36667.03, "high": 38204.77, "low": 36124.64, "close": 36854.42, "volume": 11696 },
{ "date": new Date('2025-06-27T00:00:00.000Z'), "open": 36854.42, "high": 39994.08, "low": 35636.51, "close": 38687.31, "volume": 35774 },
{ "date": new Date('2025-07-04T00:00:00.000Z'), "open": 38687.31, "high": 40457.19, "low": 37596.68, "close": 40163.67, "volume": 25878 },
{ "date": new Date('2025-07-11T00:00:00.000Z'), "open": 40163.67, "high": 41483.56, "low": 38705.45, "close": 41140.43, "volume": 27117 },
{ "date": new Date('2025-07-18T00:00:00.000Z'), "open": 41140.43, "high": 42077.75, "low": 40427.93, "close": 41384.53, "volume": 18412 },
{ "date": new Date('2025-07-25T00:00:00.000Z'), "open": 41384.53, "high": 43731.51, "low": 40676.68, "close": 42281.37, "volume": 27220 },
{ "date": new Date('2025-08-01T00:00:00.000Z'), "open": 42281.37, "high": 44193.07, "low": 40668.81, "close": 42521.88, "volume": 20782 },
{ "date": new Date('2025-08-08T00:00:00.000Z'), "open": 42521.88, "high": 44914.04, "low": 42413.5, "close": 44624.67, "volume": 38435 },
{ "date": new Date('2025-08-15T00:00:00.000Z'), "open": 44624.67, "high": 47809.23, "low": 43195.6, "close": 46315.08, "volume": 27211 },
{ "date": new Date('2025-08-22T00:00:00.000Z'), "open": 46315.08, "high": 46644.09, "low": 44044.23, "close": 45530.06, "volume": 25695 },
{ "date": new Date('2025-08-29T00:00:00.000Z'), "open": 45530.06, "high": 47471.07, "low": 44413.61, "close": 46182.89, "volume": 21888 },
{ "date": new Date('2025-09-05T00:00:00.000Z'), "open": 46182.89, "high": 47611.3, "low": 43819.07, "close": 45618.19, "volume": 22505 },
{ "date": new Date('2025-09-12T00:00:00.000Z'), "open": 45618.19, "high": 45758.19, "low": 43440.68, "close": 45193.04, "volume": 15008 },
{ "date": new Date('2025-09-19T00:00:00.000Z'), "open": 45193.04, "high": 47056.46, "low": 43900.64, "close": 46109.54, "volume": 25190 },
{ "date": new Date('2025-09-26T00:00:00.000Z'), "open": 46109.54, "high": 47923.05, "low": 44695.81, "close": 45939.86, "volume": 23493 },
{ "date": new Date('2025-10-03T00:00:00.000Z'), "open": 45939.86, "high": 47045, "low": 45729.6, "close": 46388.36, "volume": 16393 },
{ "date": new Date('2025-10-10T00:00:00.000Z'), "open": 46388.36, "high": 46744.98, "low": 44821.92, "close": 45748.38, "volume": 16663 },
{ "date": new Date('2025-10-17T00:00:00.000Z'), "open": 45748.38, "high": 47366.8, "low": 42622.68, "close": 44390.66, "volume": 29718 },
{ "date": new Date('2025-10-24T00:00:00.000Z'), "open": 44390.66, "high": 45408.03, "low": 42626.08, "close": 42850.17, "volume": 26814 },
{ "date": new Date('2025-10-31T00:00:00.000Z'), "open": 42850.17, "high": 44730.43, "low": 42764.4, "close": 44419.44, "volume": 33507 },
{ "date": new Date('2025-11-07T00:00:00.000Z'), "open": 44419.44, "high": 46177.24, "low": 43208.43, "close": 44572.36, "volume": 17894 },
{ "date": new Date('2025-11-14T00:00:00.000Z'), "open": 44572.36, "high": 45226, "low": 43169.54, "close": 45176.59, "volume": 24710 },
{ "date": new Date('2025-11-21T00:00:00.000Z'), "open": 45176.59, "high": 46681.06, "low": 44425.17, "close": 45440.96, "volume": 18897 },
{ "date": new Date('2025-11-28T00:00:00.000Z'), "open": 45440.96, "high": 46648.95, "low": 43559.13, "close": 43903.49, "volume": 30189 },
{ "date": new Date('2025-12-05T00:00:00.000Z'), "open": 43903.49, "high": 44822.92, "low": 43296.58, "close": 44812.06, "volume": 22198 },
{ "date": new Date('2025-12-12T00:00:00.000Z'), "open": 44812.06, "high": 45421.28, "low": 43680.7, "close": 44140.85, "volume": 15567 },
{ "date": new Date('2025-12-19T00:00:00.000Z'), "open": 44140.85, "high": 45712.73, "low": 41933.47, "close": 43112.95, "volume": 29974 },
{ "date": new Date('2025-12-26T00:00:00.000Z'), "open": 43112.95, "high": 46006.98, "low": 42677.78, "close": 45312.96, "volume": 38694 },
{ "date": new Date('2026-01-02T00:00:00.000Z'), "open": 45312.96, "high": 46534.77, "low": 43237.94, "close": 44432.61, "volume": 24630 },
{ "date": new Date('2026-01-09T00:00:00.000Z'), "open": 44432.61, "high": 45572.4, "low": 43427.31, "close": 45495.09, "volume": 27191 },
{ "date": new Date('2026-01-16T00:00:00.000Z'), "open": 45495.09, "high": 46637.61, "low": 43826.63, "close": 46398.47, "volume": 17656 },
{ "date": new Date('2026-01-23T00:00:00.000Z'), "open": 46398.47, "high": 46940.51, "low": 44825.25, "close": 44999.38, "volume": 23998 },
{ "date": new Date('2026-01-30T00:00:00.000Z'), "open": 44999.38, "high": 46867.75, "low": 43800, "close": 45300.84, "volume": 14133 },
{ "date": new Date('2026-02-06T00:00:00.000Z'), "open": 45300.84, "high": 47948.23, "low": 45019, "close": 46843.86, "volume": 23384 },
{ "date": new Date('2026-02-13T00:00:00.000Z'), "open": 46843.86, "high": 47907.67, "low": 44179.4, "close": 45370.85, "volume": 31541 },
{ "date": new Date('2026-02-20T00:00:00.000Z'), "open": 45370.85, "high": 46317.76, "low": 42667.3, "close": 43819.85, "volume": 25081 },
{ "date": new Date('2026-02-27T00:00:00.000Z'), "open": 43819.85, "high": 46867.83, "low": 42238.61, "close": 45456.3, "volume": 22512 },
{ "date": new Date('2026-03-06T00:00:00.000Z'), "open": 45456.3, "high": 46850.45, "low": 43984.03, "close": 45446.42, "volume": 16417 },
{ "date": new Date('2026-03-13T00:00:00.000Z'), "open": 45446.42, "high": 48351.54, "low": 44740.02, "close": 47342.35, "volume": 28002 },
{ "date": new Date('2026-03-20T00:00:00.000Z'), "open": 47342.35, "high": 48389.58, "low": 44685.98, "close": 46437.81, "volume": 18813 },
{ "date": new Date('2026-03-27T00:00:00.000Z'), "open": 46437.81, "high": 50398.91, "low": 45392.98, "close": 48764.44, "volume": 35035 },
{ "date": new Date('2026-04-03T00:00:00.000Z'), "open": 48764.44, "high": 50110.6, "low": 46924.22, "close": 47787.55, "volume": 26962 },
{ "date": new Date('2026-04-10T00:00:00.000Z'), "open": 47787.55, "high": 48190.38, "low": 46180.16, "close": 48141.15, "volume": 23273 },
{ "date": new Date('2026-04-17T00:00:00.000Z'), "open": 48141.15, "high": 49733.88, "low": 46340.81, "close": 46862.19, "volume": 19868 },
{ "date": new Date('2026-04-24T00:00:00.000Z'), "open": 46862.19, "high": 49396.09, "low": 45641.66, "close": 47811.89, "volume": 18151 },
{ "date": new Date('2026-05-01T00:00:00.000Z'), "open": 47811.89, "high": 49925.96, "low": 46202.49, "close": 48583.95, "volume": 26377 },
{ "date": new Date('2026-05-08T00:00:00.000Z'), "open": 48583.95, "high": 52115.7, "low": 48484.63, "close": 50257.54, "volume": 30637 },
{ "date": new Date('2026-05-15T00:00:00.000Z'), "open": 50257.54, "high": 50895.94, "low": 48092.55, "close": 49665, "volume": 23672 },
{ "date": new Date('2026-05-22T00:00:00.000Z'), "open": 49665, "high": 50214.97, "low": 49272.52, "close": 49766.35, "volume": 21876 },
{ "date": new Date('2026-05-29T00:00:00.000Z'), "open": 49766.35, "high": 52280.49, "low": 48181.09, "close": 50340.47, "volume": 14630 },
{ "date": new Date('2026-06-05T00:00:00.000Z'), "open": 50340.47, "high": 52307.71, "low": 47929.89, "close": 49932.93, "volume": 24466 },
{ "date": new Date('2026-06-12T00:00:00.000Z'), "open": 49932.93, "high": 52380.45, "low": 48531.27, "close": 50549.57, "volume": 20434 },
{ "date": new Date('2026-06-19T00:00:00.000Z'), "open": 50549.57, "high": 53827.85, "low": 49629.42, "close": 52022.03, "volume": 21360 },
{ "date": new Date('2026-06-26T00:00:00.000Z'), "open": 52022.03, "high": 53183.16, "low": 51692.65, "close": 51871.98, "volume": 12907 },
{ "date": new Date('2026-07-03T00:00:00.000Z'), "open": 51871.98, "high": 53220.21, "low": 50522.52, "close": 52831.12, "volume": 26315 },
{ "date": new Date('2026-07-10T00:00:00.000Z'), "open": 52831.12, "high": 54511.37, "low": 50626.84, "close": 51387.24, "volume": 27641 },
{ "date": new Date('2026-07-17T00:00:00.000Z'), "open": 51387.24, "high": 52293.32, "low": 50883.73, "close": 52205.27, "volume": 21506 },
{ "date": new Date('2026-07-24T00:00:00.000Z'), "open": 52205.27, "high": 53366.75, "low": 49555.71, "close": 50697.81, "volume": 31841 },
{ "date": new Date('2026-07-31T00:00:00.000Z'), "open": 50697.81, "high": 50830.35, "low": 47679.04, "close": 49072.59, "volume": 30827 },
{ "date": new Date('2026-08-07T00:00:00.000Z'), "open": 49072.59, "high": 49759.9, "low": 47737.67, "close": 48971.94, "volume": 13451 },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "open": 48971.94, "high": 50706.99, "low": 48042.28, "close": 50623.48, "volume": 22495 },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "open": 50623.48, "high": 52545.56, "low": 50246.04, "close": 52481.37, "volume": 31927 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "open": 52481.37, "high": 54175.35, "low": 50911.84, "close": 52835.86, "volume": 15392 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "open": 52835.86, "high": 54335.97, "low": 51814.95, "close": 53663.18, "volume": 23203 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "open": 53663.18, "high": 55387.45, "low": 52001.71, "close": 52157.23, "volume": 20064 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "open": 52157.23, "high": 54902.72, "low": 50300.45, "close": 53350.3, "volume": 23440 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "open": 53350.3, "high": 54167.95, "low": 51842.92, "close": 52456.67, "volume": 19192 },
] },
{ "id": "previous", "label": "Last period", "data": [
{ "date": new Date('2014-10-17T00:00:00.000Z'), "open": 3276, "high": 3285.06, "low": 3105.45, "close": 3187, "volume": 18939 },
{ "date": new Date('2014-10-24T00:00:00.000Z'), "open": 3516.1, "high": 3546.58, "low": 3421.43, "close": 3493.88, "volume": 22201 },
{ "date": new Date('2014-10-31T00:00:00.000Z'), "open": 3341.85, "high": 3473.15, "low": 3245.93, "close": 3471.89, "volume": 22282 },
{ "date": new Date('2014-11-07T00:00:00.000Z'), "open": 3047.72, "high": 3169.4, "low": 2862.75, "close": 2963.5, "volume": 19300 },
{ "date": new Date('2014-11-14T00:00:00.000Z'), "open": 2896.42, "high": 2993.93, "low": 2843.35, "close": 2987.24, "volume": 21532 },
{ "date": new Date('2014-11-21T00:00:00.000Z'), "open": 3375.61, "high": 3586.43, "low": 3259.96, "close": 3555.76, "volume": 25860 },
{ "date": new Date('2014-11-28T00:00:00.000Z'), "open": 3847.5, "high": 3969.53, "low": 3753.68, "close": 3777.72, "volume": 23050 },
{ "date": new Date('2014-12-05T00:00:00.000Z'), "open": 3529.29, "high": 3602, "low": 3387.77, "close": 3522.73, "volume": 17498 },
{ "date": new Date('2014-12-12T00:00:00.000Z'), "open": 3104.15, "high": 3364.7, "low": 3022.97, "close": 3244.71, "volume": 26637 },
{ "date": new Date('2014-12-19T00:00:00.000Z'), "open": 3269.83, "high": 3392.74, "low": 3228.67, "close": 3363.15, "volume": 19798 },
{ "date": new Date('2014-12-26T00:00:00.000Z'), "open": 3826.99, "high": 4154.9, "low": 3701.5, "close": 4000.68, "volume": 28735 },
{ "date": new Date('2015-01-02T00:00:00.000Z'), "open": 4233.09, "high": 4389, "low": 4170.61, "close": 4205.3, "volume": 15785 },
{ "date": new Date('2015-01-09T00:00:00.000Z'), "open": 3847.11, "high": 4015.54, "low": 3741.16, "close": 3989.5, "volume": 28197 },
{ "date": new Date('2015-01-16T00:00:00.000Z'), "open": 3551.3, "high": 3675.03, "low": 3467.63, "close": 3674.28, "volume": 21024 },
{ "date": new Date('2015-01-23T00:00:00.000Z'), "open": 3816.06, "high": 3997.55, "low": 3770.84, "close": 3939.79, "volume": 16550 },
{ "date": new Date('2015-01-30T00:00:00.000Z'), "open": 4486.12, "high": 4522.81, "low": 4219.01, "close": 4332.7, "volume": 19728 },
{ "date": new Date('2015-02-06T00:00:00.000Z'), "open": 4473.6, "high": 4720.37, "low": 4347.73, "close": 4547.73, "volume": 16235 },
{ "date": new Date('2015-02-13T00:00:00.000Z'), "open": 4087.98, "high": 4209.1, "low": 3918.22, "close": 4007.73, "volume": 16713 },
{ "date": new Date('2015-02-20T00:00:00.000Z'), "open": 3626.15, "high": 3748.12, "low": 3416.78, "close": 3521.19, "volume": 22424 },
{ "date": new Date('2015-02-27T00:00:00.000Z'), "open": 3760.63, "high": 3870.99, "low": 3735.29, "close": 3867.35, "volume": 22016 },
{ "date": new Date('2015-03-06T00:00:00.000Z'), "open": 4380.12, "high": 4513.96, "low": 4306.52, "close": 4474.35, "volume": 18076 },
{ "date": new Date('2015-03-13T00:00:00.000Z'), "open": 4503.05, "high": 4604.41, "low": 4261.15, "close": 4440.04, "volume": 13462 },
{ "date": new Date('2015-03-20T00:00:00.000Z'), "open": 3938.7, "high": 4130.33, "low": 3920.92, "close": 4049.73, "volume": 25306 },
{ "date": new Date('2015-03-27T00:00:00.000Z'), "open": 3744.86, "high": 3912.83, "low": 3596.55, "close": 3807.97, "volume": 19017 },
{ "date": new Date('2015-04-03T00:00:00.000Z'), "open": 4166.27, "high": 4368.5, "low": 4155.77, "close": 4335.37, "volume": 27027 },
{ "date": new Date('2015-04-10T00:00:00.000Z'), "open": 4857.44, "high": 5075.13, "low": 4719.32, "close": 4957.13, "volume": 23394 },
{ "date": new Date('2015-04-17T00:00:00.000Z'), "open": 4861.67, "high": 5070.18, "low": 4817.65, "close": 4951.04, "volume": 22711 },
{ "date": new Date('2015-04-24T00:00:00.000Z'), "open": 4356.46, "high": 4527.97, "low": 4158.1, "close": 4282.76, "volume": 13095 },
{ "date": new Date('2015-05-01T00:00:00.000Z'), "open": 4065.61, "high": 4217.65, "low": 3948.99, "close": 3974.37, "volume": 17118 },
{ "date": new Date('2015-05-08T00:00:00.000Z'), "open": 4432.21, "high": 4480.5, "low": 4297.91, "close": 4299.93, "volume": 25241 },
{ "date": new Date('2015-05-15T00:00:00.000Z'), "open": 4743.51, "high": 4859.77, "low": 4631.09, "close": 4810.13, "volume": 24041 },
{ "date": new Date('2015-05-22T00:00:00.000Z'), "open": 4600.36, "high": 4644.5, "low": 4400.11, "close": 4497.39, "volume": 16119 },
{ "date": new Date('2015-05-29T00:00:00.000Z'), "open": 3947.94, "high": 4061.8, "low": 3851.7, "close": 3982.24, "volume": 14321 },
{ "date": new Date('2015-06-05T00:00:00.000Z'), "open": 3892.59, "high": 3910.5, "low": 3664.19, "close": 3759.95, "volume": 19875 },
{ "date": new Date('2015-06-12T00:00:00.000Z'), "open": 4248.96, "high": 4371.72, "low": 4228.74, "close": 4287.1, "volume": 19877 },
{ "date": new Date('2015-06-19T00:00:00.000Z'), "open": 4638.45, "high": 4902.55, "low": 4490.28, "close": 4854.2, "volume": 29544 },
{ "date": new Date('2015-06-26T00:00:00.000Z'), "open": 4534.56, "high": 4581.13, "low": 4435.96, "close": 4520.4, "volume": 14539 },
{ "date": new Date('2015-07-03T00:00:00.000Z'), "open": 3983.39, "high": 4063.41, "low": 3963.7, "close": 4033.05, "volume": 12126 },
{ "date": new Date('2015-07-10T00:00:00.000Z'), "open": 4064.78, "high": 4271.73, "low": 3945.82, "close": 4221.13, "volume": 24853 },
{ "date": new Date('2015-07-17T00:00:00.000Z'), "open": 4803.38, "high": 4988.56, "low": 4680.56, "close": 4963.33, "volume": 27430 },
{ "date": new Date('2015-07-24T00:00:00.000Z'), "open": 5251.16, "high": 5591.03, "low": 5226.81, "close": 5375.89, "volume": 24783 },
{ "date": new Date('2015-07-31T00:00:00.000Z'), "open": 4917.61, "high": 5074.14, "low": 4657.77, "close": 4815.11, "volume": 17466 },
{ "date": new Date('2015-08-07T00:00:00.000Z'), "open": 4286.52, "high": 4445.81, "low": 4170.77, "close": 4337.72, "volume": 18928 },
{ "date": new Date('2015-08-14T00:00:00.000Z'), "open": 4505.64, "high": 4507.65, "low": 4442.63, "close": 4460.78, "volume": 18673 },
{ "date": new Date('2015-08-21T00:00:00.000Z'), "open": 5079.31, "high": 5414.75, "low": 5040.29, "close": 5213.25, "volume": 18351 },
{ "date": new Date('2015-08-28T00:00:00.000Z'), "open": 5382.25, "high": 5666.49, "low": 5354.4, "close": 5605.86, "volume": 23843 },
{ "date": new Date('2015-09-04T00:00:00.000Z'), "open": 5038.83, "high": 5132.4, "low": 4854.38, "close": 5128.19, "volume": 15911 },
{ "date": new Date('2015-09-11T00:00:00.000Z'), "open": 4640.3, "high": 4942.26, "low": 4626.97, "close": 4865.29, "volume": 21443 },
{ "date": new Date('2015-09-18T00:00:00.000Z'), "open": 5196.68, "high": 5554.19, "low": 5166.24, "close": 5419.1, "volume": 23500 },
{ "date": new Date('2015-09-25T00:00:00.000Z'), "open": 6137.4, "high": 6247.43, "low": 6038.14, "close": 6165.88, "volume": 19677 },
{ "date": new Date('2015-10-02T00:00:00.000Z'), "open": 6204.78, "high": 6324.4, "low": 6078.72, "close": 6175.09, "volume": 19994 },
{ "date": new Date('2015-10-09T00:00:00.000Z'), "open": 5477.6, "high": 5582.5, "low": 5286.96, "close": 5508.84, "volume": 11881 },
{ "date": new Date('2015-10-16T00:00:00.000Z'), "open": 5094.62, "high": 5203.71, "low": 4924.38, "close": 5176.88, "volume": 14172 },
{ "date": new Date('2015-10-23T00:00:00.000Z'), "open": 5664.49, "high": 5992.8, "low": 5580.1, "close": 5948.74, "volume": 21569 },
{ "date": new Date('2015-10-30T00:00:00.000Z'), "open": 6664.72, "high": 7107.4, "low": 6488.83, "close": 7001.15, "volume": 31333 },
{ "date": new Date('2015-11-06T00:00:00.000Z'), "open": 6865.61, "high": 7265.49, "low": 6619.09, "close": 7204.49, "volume": 27968 },
{ "date": new Date('2015-11-13T00:00:00.000Z'), "open": 6339.14, "high": 6439.9, "low": 6068.55, "close": 6146.7, "volume": 16164 },
{ "date": new Date('2015-11-20T00:00:00.000Z'), "open": 5835.7, "high": 5879.86, "low": 5518.95, "close": 5638.69, "volume": 23100 },
{ "date": new Date('2015-11-27T00:00:00.000Z'), "open": 6288.67, "high": 6647.7, "low": 6084.8, "close": 6598.3, "volume": 31775 },
{ "date": new Date('2015-12-04T00:00:00.000Z'), "open": 7278.4, "high": 7436.68, "low": 7020, "close": 7293.32, "volume": 18976 },
{ "date": new Date('2015-12-11T00:00:00.000Z'), "open": 6974.56, "high": 7253.56, "low": 6924.47, "close": 7185.98, "volume": 26208 },
{ "date": new Date('2015-12-18T00:00:00.000Z'), "open": 6308.08, "high": 6578.35, "low": 6282.65, "close": 6430.86, "volume": 17452 },
{ "date": new Date('2015-12-25T00:00:00.000Z'), "open": 6286.85, "high": 6484.35, "low": 6224.37, "close": 6345.6, "volume": 13111 },
{ "date": new Date('2016-01-01T00:00:00.000Z'), "open": 7171.19, "high": 7423.48, "low": 7013.47, "close": 7252.39, "volume": 21297 },
{ "date": new Date('2016-01-08T00:00:00.000Z'), "open": 7846.07, "high": 8404.38, "low": 7838.04, "close": 8111.72, "volume": 27278 },
{ "date": new Date('2016-01-15T00:00:00.000Z'), "open": 7576.89, "high": 7672.19, "low": 7350.49, "close": 7504.97, "volume": 11450 },
{ "date": new Date('2016-01-22T00:00:00.000Z'), "open": 6613.59, "high": 6928.36, "low": 6480.23, "close": 6710.4, "volume": 13273 },
{ "date": new Date('2016-01-29T00:00:00.000Z'), "open": 6764, "high": 7027.25, "low": 6762.1, "close": 6911.62, "volume": 16086 },
{ "date": new Date('2016-02-05T00:00:00.000Z'), "open": 7865.1, "high": 7909, "low": 7712.81, "close": 7877.55, "volume": 11871 },
{ "date": new Date('2016-02-12T00:00:00.000Z'), "open": 8333.56, "high": 8660.8, "low": 7895.56, "close": 8145.23, "volume": 17736 },
{ "date": new Date('2016-02-19T00:00:00.000Z'), "open": 7450.27, "high": 7779.59, "low": 7409.86, "close": 7533.86, "volume": 17207 },
{ "date": new Date('2016-02-26T00:00:00.000Z'), "open": 6707.17, "high": 6891.99, "low": 6467.77, "close": 6817.28, "volume": 14576 },
{ "date": new Date('2016-03-04T00:00:00.000Z'), "open": 7082.04, "high": 7101.1, "low": 6943.49, "close": 7009.81, "volume": 19029 },
{ "date": new Date('2016-03-11T00:00:00.000Z'), "open": 7981.69, "high": 8278.83, "low": 7873.23, "close": 8106.51, "volume": 23635 },
{ "date": new Date('2016-03-18T00:00:00.000Z'), "open": 8368.44, "high": 8823.92, "low": 8183.17, "close": 8573.04, "volume": 20102 },
{ "date": new Date('2016-03-25T00:00:00.000Z'), "open": 7705.38, "high": 7865, "low": 7444.77, "close": 7458.59, "volume": 21322 },
{ "date": new Date('2016-04-01T00:00:00.000Z'), "open": 6749.52, "high": 7003.11, "low": 6692.73, "close": 6965.36, "volume": 21079 },
{ "date": new Date('2016-04-08T00:00:00.000Z'), "open": 7440.61, "high": 7660.93, "low": 7134.84, "close": 7216.26, "volume": 22812 },
{ "date": new Date('2016-04-15T00:00:00.000Z'), "open": 8172.52, "high": 8233.09, "low": 7906.76, "close": 8128.19, "volume": 14323 },
{ "date": new Date('2016-04-22T00:00:00.000Z'), "open": 8178.6, "high": 8483.42, "low": 8078, "close": 8108.8, "volume": 14589 },
{ "date": new Date('2016-04-29T00:00:00.000Z'), "open": 7192.6, "high": 7655.31, "low": 7020.36, "close": 7359.09, "volume": 14854 },
{ "date": new Date('2016-05-06T00:00:00.000Z'), "open": 6806.43, "high": 7172.38, "low": 6667.31, "close": 7141.98, "volume": 23429 },
{ "date": new Date('2016-05-13T00:00:00.000Z'), "open": 7815.38, "high": 7873.12, "low": 7704.83, "close": 7809.86, "volume": 18590 },
{ "date": new Date('2016-05-20T00:00:00.000Z'), "open": 8749.37, "high": 9137.71, "low": 8402.81, "close": 8886.19, "volume": 24819 },
{ "date": new Date('2016-05-27T00:00:00.000Z'), "open": 8713.24, "high": 8832.34, "low": 8255.58, "close": 8496.61, "volume": 25242 },
{ "date": new Date('2016-06-03T00:00:00.000Z'), "open": 7475.9, "high": 7602.82, "low": 7197.76, "close": 7426.81, "volume": 13114 },
{ "date": new Date('2016-06-10T00:00:00.000Z'), "open": 7051.87, "high": 7130.07, "low": 6744.55, "close": 6944.31, "volume": 17190 },
{ "date": new Date('2016-06-17T00:00:00.000Z'), "open": 7745.31, "high": 8222.1, "low": 7687.65, "close": 8064.6, "volume": 24110 },
{ "date": new Date('2016-06-24T00:00:00.000Z'), "open": 8895.26, "high": 9110.91, "low": 8622.26, "close": 8800.1, "volume": 18740 },
{ "date": new Date('2016-07-01T00:00:00.000Z'), "open": 8414.6, "high": 8957.9, "low": 8350.7, "close": 8701.89, "volume": 26480 },
{ "date": new Date('2016-07-08T00:00:00.000Z'), "open": 7638.82, "high": 7908, "low": 7435.63, "close": 7622.87, "volume": 14143 },
{ "date": new Date('2016-07-15T00:00:00.000Z'), "open": 7453.1, "high": 7638.75, "low": 7281.29, "close": 7372.71, "volume": 15972 },
{ "date": new Date('2016-07-22T00:00:00.000Z'), "open": 8332.28, "high": 8890.16, "low": 8027.91, "close": 8663.28, "volume": 24587 },
{ "date": new Date('2016-07-29T00:00:00.000Z'), "open": 9371.65, "high": 9497.28, "low": 9051.17, "close": 9071.75, "volume": 20990 },
{ "date": new Date('2016-08-05T00:00:00.000Z'), "open": 8472.84, "high": 8659.4, "low": 8413.7, "close": 8462.7, "volume": 19123 },
{ "date": new Date('2016-08-12T00:00:00.000Z'), "open": 7457.79, "high": 7874.7, "low": 7373.44, "close": 7732.74, "volume": 20499 },
{ "date": new Date('2016-08-19T00:00:00.000Z'), "open": 7795.54, "high": 8230.59, "low": 7507.64, "close": 8096.4, "volume": 17465 },
{ "date": new Date('2016-08-26T00:00:00.000Z'), "open": 9213.5, "high": 9601.62, "low": 9120.73, "close": 9527.35, "volume": 22004 },
{ "date": new Date('2016-09-02T00:00:00.000Z'), "open": 10077.89, "high": 10282.53, "low": 9663.9, "close": 10060.56, "volume": 15598 },
{ "date": new Date('2016-09-09T00:00:00.000Z'), "open": 9201.45, "high": 9848.81, "low": 9187.68, "close": 9685.94, "volume": 30338 },
{ "date": new Date('2016-09-16T00:00:00.000Z'), "open": 8623.59, "high": 9237.05, "low": 8299.22, "close": 9042.99, "volume": 25374 },
{ "date": new Date('2016-09-23T00:00:00.000Z'), "open": 9395.31, "high": 10230.16, "low": 9189.66, "close": 9848.33, "volume": 29410 },
{ "date": new Date('2016-09-30T00:00:00.000Z'), "open": 11213.65, "high": 11298.13, "low": 10690.83, "close": 10929.51, "volume": 23266 },
{ "date": new Date('2016-10-07T00:00:00.000Z'), "open": 11281.5, "high": 11480.4, "low": 10807.3, "close": 11104.76, "volume": 24081 },
{ "date": new Date('2016-10-14T00:00:00.000Z'), "open": 9980.24, "high": 10601.58, "low": 9642.31, "close": 10493.31, "volume": 27523 },
{ "date": new Date('2016-10-21T00:00:00.000Z'), "open": 9496.49, "high": 9686.56, "low": 9147.82, "close": 9634.95, "volume": 13056 },
{ "date": new Date('2016-10-28T00:00:00.000Z'), "open": 10293.44, "high": 10986.51, "low": 10012.4, "close": 10609.32, "volume": 20123 },
{ "date": new Date('2016-11-04T00:00:00.000Z'), "open": 12014.81, "high": 12981.86, "low": 11893.11, "close": 12635.45, "volume": 33880 },
{ "date": new Date('2016-11-11T00:00:00.000Z'), "open": 12712.47, "high": 12853.23, "low": 12045.92, "close": 12278.63, "volume": 19937 },
{ "date": new Date('2016-11-18T00:00:00.000Z'), "open": 10890.77, "high": 11463.46, "low": 10774, "close": 11366.93, "volume": 29445 },
{ "date": new Date('2016-11-25T00:00:00.000Z'), "open": 10514.33, "high": 10688.05, "low": 10279.03, "close": 10507.99, "volume": 8059 },
{ "date": new Date('2016-12-02T00:00:00.000Z'), "open": 11499.78, "high": 12171.58, "low": 11487.9, "close": 12047.05, "volume": 30557 },
{ "date": new Date('2016-12-09T00:00:00.000Z'), "open": 13495.54, "high": 14039.08, "low": 13064.89, "close": 13154.04, "volume": 24329 },
{ "date": new Date('2016-12-16T00:00:00.000Z'), "open": 12896.67, "high": 13044.24, "low": 12813.74, "close": 12963.84, "volume": 21568 },
{ "date": new Date('2016-12-23T00:00:00.000Z'), "open": 11406.24, "high": 11461.5, "low": 11230.3, "close": 11231.05, "volume": 12466 },
{ "date": new Date('2016-12-30T00:00:00.000Z'), "open": 10665.27, "high": 11200.04, "low": 10250.73, "close": 10872.93, "volume": 12979 },
{ "date": new Date('2017-01-06T00:00:00.000Z'), "open": 12127.89, "high": 13103.25, "low": 11894.04, "close": 12720.2, "volume": 23450 },
{ "date": new Date('2017-01-13T00:00:00.000Z'), "open": 14029.3, "high": 14992.83, "low": 13533.15, "close": 14786.43, "volume": 34650 },
{ "date": new Date('2017-01-20T00:00:00.000Z'), "open": 14137.34, "high": 15097.12, "low": 13706.17, "close": 14542.06, "volume": 17096 },
{ "date": new Date('2017-01-27T00:00:00.000Z'), "open": 12765.55, "high": 13185.17, "low": 12543.21, "close": 12838.24, "volume": 15918 },
{ "date": new Date('2017-02-03T00:00:00.000Z'), "open": 12553.87, "high": 12749.5, "low": 12154.71, "close": 12393.28, "volume": 14728 },
{ "date": new Date('2017-02-10T00:00:00.000Z'), "open": 14006.86, "high": 14683.94, "low": 13941.76, "close": 14625.59, "volume": 31254 },
{ "date": new Date('2017-02-17T00:00:00.000Z'), "open": 15820.12, "high": 16473.86, "low": 15288.4, "close": 16167.06, "volume": 19985 },
{ "date": new Date('2017-02-24T00:00:00.000Z'), "open": 15098.34, "high": 15363.56, "low": 15091.8, "close": 15354.41, "volume": 17777 },
{ "date": new Date('2017-03-03T00:00:00.000Z'), "open": 13531.52, "high": 13949.8, "low": 13176.01, "close": 13891.15, "volume": 19176 },
{ "date": new Date('2017-03-10T00:00:00.000Z'), "open": 14005.72, "high": 14312.27, "low": 13915.8, "close": 13978.92, "volume": 9020 },
{ "date": new Date('2017-03-17T00:00:00.000Z'), "open": 15907.85, "high": 16740.48, "low": 15520.3, "close": 16341.6, "volume": 20488 },
{ "date": new Date('2017-03-24T00:00:00.000Z'), "open": 17284.3, "high": 17762.92, "low": 16502.96, "close": 16811.74, "volume": 19921 },
{ "date": new Date('2017-03-31T00:00:00.000Z'), "open": 15374.91, "high": 16064.48, "low": 15161.49, "close": 16050.15, "volume": 25590 },
{ "date": new Date('2017-04-07T00:00:00.000Z'), "open": 14290.54, "high": 14525.36, "low": 13514.67, "close": 13835.22, "volume": 23807 },
{ "date": new Date('2017-04-14T00:00:00.000Z'), "open": 14375.97, "high": 14473.3, "low": 13524.48, "close": 13987.39, "volume": 23527 },
{ "date": new Date('2017-04-21T00:00:00.000Z'), "open": 15926.37, "high": 15954.89, "low": 15084.97, "close": 15454.13, "volume": 28211 },
{ "date": new Date('2017-04-28T00:00:00.000Z'), "open": 15950.18, "high": 17160.91, "low": 15807.56, "close": 16822.63, "volume": 33388 },
{ "date": new Date('2017-05-05T00:00:00.000Z'), "open": 15118.14, "high": 15686.48, "low": 14246.01, "close": 14819.26, "volume": 20109 },
{ "date": new Date('2017-05-12T00:00:00.000Z'), "open": 13412.55, "high": 13881.3, "low": 12630.49, "close": 12948.18, "volume": 23314 },
{ "date": new Date('2017-05-19T00:00:00.000Z'), "open": 13834.6, "high": 14005.94, "low": 13034.13, "close": 13356.2, "volume": 21076 },
{ "date": new Date('2017-05-26T00:00:00.000Z'), "open": 15125.09, "high": 16049.95, "low": 14874.97, "close": 15646.51, "volume": 20765 },
{ "date": new Date('2017-06-02T00:00:00.000Z'), "open": 15740.22, "high": 16653.81, "low": 15680.5, "close": 16507.91, "volume": 25429 },
{ "date": new Date('2017-06-09T00:00:00.000Z'), "open": 14641.37, "high": 14669.02, "low": 13790.53, "close": 14281.1, "volume": 17323 },
{ "date": new Date('2017-06-16T00:00:00.000Z'), "open": 13211.3, "high": 13721.6, "low": 12966.5, "close": 13121.5, "volume": 17710 },
{ "date": new Date('2017-06-23T00:00:00.000Z'), "open": 14361.3, "high": 15213.48, "low": 14232.66, "close": 14820.73, "volume": 19254 },
{ "date": new Date('2017-06-30T00:00:00.000Z'), "open": 16601.82, "high": 17263.85, "low": 16365.67, "close": 16639.45, "volume": 19691 },
{ "date": new Date('2017-07-07T00:00:00.000Z'), "open": 16312.18, "high": 16636.24, "low": 15975.68, "close": 16525.64, "volume": 12988 },
{ "date": new Date('2017-07-14T00:00:00.000Z'), "open": 14539.77, "high": 14694.17, "low": 13893.45, "close": 14335.36, "volume": 12881 },
{ "date": new Date('2017-07-21T00:00:00.000Z'), "open": 13614.76, "high": 14423.77, "low": 13109.87, "close": 14182.96, "volume": 22934 },
{ "date": new Date('2017-07-28T00:00:00.000Z'), "open": 15821.01, "high": 16418.61, "low": 14964.54, "close": 15506, "volume": 13763 },
{ "date": new Date('2017-08-04T00:00:00.000Z'), "open": 17100.7, "high": 17373.99, "low": 16849.53, "close": 17005.36, "volume": 14461 },
{ "date": new Date('2017-08-11T00:00:00.000Z'), "open": 16257.24, "high": 16944.45, "low": 16234.77, "close": 16698.2, "volume": 21802 },
{ "date": new Date('2017-08-18T00:00:00.000Z'), "open": 14658.34, "high": 15264.03, "low": 14392.96, "close": 14996.19, "volume": 14773 },
{ "date": new Date('2017-08-25T00:00:00.000Z'), "open": 14665.84, "high": 14998.14, "low": 14167.16, "close": 14527.46, "volume": 19381 },
{ "date": new Date('2017-09-01T00:00:00.000Z'), "open": 16419.58, "high": 16784, "low": 15536.67, "close": 15918.05, "volume": 22634 },
{ "date": new Date('2017-09-08T00:00:00.000Z'), "open": 17216.65, "high": 17743.3, "low": 16435.09, "close": 16750.56, "volume": 28380 },
{ "date": new Date('2017-09-15T00:00:00.000Z'), "open": 15641.83, "high": 16633.87, "low": 15312.69, "close": 16298.99, "volume": 25084 },
{ "date": new Date('2017-09-22T00:00:00.000Z'), "open": 14364.38, "high": 14811.03, "low": 13644.12, "close": 14158.6, "volume": 17362 },
{ "date": new Date('2017-09-29T00:00:00.000Z'), "open": 14277.17, "high": 14812.25, "low": 13689.96, "close": 13970.45, "volume": 15292 },
{ "date": new Date('2017-10-06T00:00:00.000Z'), "open": 15898.45, "high": 16064.21, "low": 15116.85, "close": 15574.46, "volume": 24833 },
{ "date": new Date('2017-10-13T00:00:00.000Z'), "open": 16471.25, "high": 17640.3, "low": 16062.61, "close": 16957.4, "volume": 25112 },
{ "date": new Date('2017-10-20T00:00:00.000Z'), "open": 15506.9, "high": 15870.3, "low": 15466.87, "close": 15779.7, "volume": 13924 },
{ "date": new Date('2017-10-27T00:00:00.000Z'), "open": 14050.52, "high": 15235.99, "low": 14018.78, "close": 14650.94, "volume": 20360 },
{ "date": new Date('2017-11-03T00:00:00.000Z'), "open": 15225.41, "high": 15498.86, "low": 14627.87, "close": 14936.63, "volume": 14852 },
{ "date": new Date('2017-11-10T00:00:00.000Z'), "open": 17007.02, "high": 17537.12, "low": 16267.79, "close": 16451.36, "volume": 24522 },
{ "date": new Date('2017-11-17T00:00:00.000Z'), "open": 16977.66, "high": 17623.32, "low": 16666.99, "close": 17037.38, "volume": 11400 },
{ "date": new Date('2017-11-24T00:00:00.000Z'), "open": 15310.16, "high": 16152.77, "low": 15215.21, "close": 15577.21, "volume": 20229 },
{ "date": new Date('2017-12-01T00:00:00.000Z'), "open": 14099.66, "high": 14714.6, "low": 14077.52, "close": 14645.57, "volume": 25049 },
{ "date": new Date('2017-12-08T00:00:00.000Z'), "open": 15649.87, "high": 16109.59, "low": 14804.36, "close": 15416.93, "volume": 13653 },
{ "date": new Date('2017-12-15T00:00:00.000Z'), "open": 17458.14, "high": 18977.7, "low": 17181.57, "close": 18379.55, "volume": 27723 },
{ "date": new Date('2017-12-22T00:00:00.000Z'), "open": 18487.65, "high": 19090.1, "low": 18003.05, "close": 18279.68, "volume": 23794 },
{ "date": new Date('2017-12-29T00:00:00.000Z'), "open": 16212.1, "high": 16231.44, "low": 15548.77, "close": 15871.06, "volume": 20425 },
{ "date": new Date('2018-01-05T00:00:00.000Z'), "open": 14683.54, "high": 15605.3, "low": 14154.04, "close": 15198.16, "volume": 23964 },
{ "date": new Date('2018-01-12T00:00:00.000Z'), "open": 16635.6, "high": 17364.78, "low": 16255.46, "close": 16727.72, "volume": 19286 },
{ "date": new Date('2018-01-19T00:00:00.000Z'), "open": 18736.95, "high": 19244.03, "low": 17999.7, "close": 18623.69, "volume": 16121 },
{ "date": new Date('2018-01-26T00:00:00.000Z'), "open": 18255.47, "high": 18369.18, "low": 18230.55, "close": 18332.87, "volume": 12938 },
{ "date": new Date('2018-02-02T00:00:00.000Z'), "open": 16129.48, "high": 16719.99, "low": 15756.06, "close": 16152.58, "volume": 15285 },
{ "date": new Date('2018-02-09T00:00:00.000Z'), "open": 15342.4, "high": 15868.52, "low": 14322.79, "close": 14859.72, "volume": 22082 },
{ "date": new Date('2018-02-16T00:00:00.000Z'), "open": 16577.04, "high": 16592.98, "low": 15427.22, "close": 16067.08, "volume": 25685 },
{ "date": new Date('2018-02-23T00:00:00.000Z'), "open": 17718.13, "high": 18965.1, "low": 17666.8, "close": 18453.82, "volume": 30573 },
{ "date": new Date('2018-03-02T00:00:00.000Z'), "open": 17640.21, "high": 18334, "low": 16974.46, "close": 18326.1, "volume": 30142 },
{ "date": new Date('2018-03-09T00:00:00.000Z'), "open": 16087.4, "high": 16567.41, "low": 15376.87, "close": 15973.72, "volume": 17907 },
{ "date": new Date('2018-03-16T00:00:00.000Z'), "open": 15623.77, "high": 17048.21, "low": 15347.09, "close": 16442.01, "volume": 21102 },
{ "date": new Date('2018-03-23T00:00:00.000Z'), "open": 18584.25, "high": 19925.1, "low": 17877.1, "close": 19441.22, "volume": 28766 },
{ "date": new Date('2018-03-30T00:00:00.000Z'), "open": 21025.42, "high": 21682.75, "low": 20872.57, "close": 21455.42, "volume": 16467 },
{ "date": new Date('2018-04-06T00:00:00.000Z'), "open": 20033.44, "high": 20831.41, "low": 18776.6, "close": 19445.32, "volume": 20221 },
{ "date": new Date('2018-04-13T00:00:00.000Z'), "open": 17137.75, "high": 17609.69, "low": 16690.89, "close": 16768.88, "volume": 22483 },
{ "date": new Date('2018-04-20T00:00:00.000Z'), "open": 16911.43, "high": 18129.54, "low": 16359.03, "close": 17616.28, "volume": 19787 },
{ "date": new Date('2018-04-27T00:00:00.000Z'), "open": 20047.73, "high": 20503.05, "low": 19471.35, "close": 19669.39, "volume": 23450 },
{ "date": new Date('2018-05-04T00:00:00.000Z'), "open": 20799.96, "high": 20929.32, "low": 19933.85, "close": 20234.5, "volume": 17982 },
{ "date": new Date('2018-05-11T00:00:00.000Z'), "open": 18502.2, "high": 19314.5, "low": 18349.6, "close": 18826.75, "volume": 23008 },
{ "date": new Date('2018-05-18T00:00:00.000Z'), "open": 16764.59, "high": 17373.36, "low": 16464.68, "close": 16760.6, "volume": 13532 },
{ "date": new Date('2018-05-25T00:00:00.000Z'), "open": 17419.87, "high": 18374.56, "low": 16835, "close": 18121.59, "volume": 21349 },
{ "date": new Date('2018-06-01T00:00:00.000Z'), "open": 20633.23, "high": 21198.51, "low": 20582.78, "close": 20903.7, "volume": 20998 },
{ "date": new Date('2018-06-08T00:00:00.000Z'), "open": 21570.22, "high": 21776.18, "low": 20927.7, "close": 21736.68, "volume": 15234 },
{ "date": new Date('2018-06-15T00:00:00.000Z'), "open": 19531.82, "high": 20150.5, "low": 19149.57, "close": 19688.07, "volume": 12952 },
{ "date": new Date('2018-06-22T00:00:00.000Z'), "open": 17822.01, "high": 18117.37, "low": 17710.5, "close": 17965.42, "volume": 16758 },
{ "date": new Date('2018-06-29T00:00:00.000Z'), "open": 19199.43, "high": 19812.83, "low": 19086.31, "close": 19441.17, "volume": 19834 },
{ "date": new Date('2018-07-06T00:00:00.000Z'), "open": 22014.44, "high": 22536.21, "low": 21895.46, "close": 21961.95, "volume": 19198 },
{ "date": new Date('2018-07-13T00:00:00.000Z'), "open": 22088.79, "high": 22818.52, "low": 21814.45, "close": 22462.68, "volume": 22880 },
{ "date": new Date('2018-07-20T00:00:00.000Z'), "open": 19921.09, "high": 20384.71, "low": 19548.08, "close": 20040.73, "volume": 10736 },
{ "date": new Date('2018-07-27T00:00:00.000Z'), "open": 18543.06, "high": 19337.27, "low": 18137.84, "close": 18589.18, "volume": 11109 },
{ "date": new Date('2018-08-03T00:00:00.000Z'), "open": 20349.15, "high": 20593.69, "low": 19505.04, "close": 20246.37, "volume": 13927 },
{ "date": new Date('2018-08-10T00:00:00.000Z'), "open": 22677, "high": 23620.25, "low": 21920.61, "close": 23554.12, "volume": 23703 },
{ "date": new Date('2018-08-17T00:00:00.000Z'), "open": 23085.99, "high": 25234.13, "low": 22268.96, "close": 24322.04, "volume": 30850 },
{ "date": new Date('2018-08-24T00:00:00.000Z'), "open": 21398.37, "high": 23385.12, "low": 21047.7, "close": 22525.49, "volume": 26187 },
{ "date": new Date('2018-08-31T00:00:00.000Z'), "open": 21398.11, "high": 22219.08, "low": 20798.16, "close": 22216.54, "volume": 25483 },
{ "date": new Date('2018-09-07T00:00:00.000Z'), "open": 24785.71, "high": 25836.51, "low": 24688.79, "close": 24898.19, "volume": 13230 },
{ "date": new Date('2018-09-14T00:00:00.000Z'), "open": 27454.74, "high": 27765.46, "low": 26932.96, "close": 27239.43, "volume": 22087 },
{ "date": new Date('2018-09-21T00:00:00.000Z'), "open": 26035.87, "high": 26889.78, "low": 25209.5, "close": 26042.69, "volume": 15979 },
{ "date": new Date('2018-09-28T00:00:00.000Z'), "open": 22861.45, "high": 23150.48, "low": 22407.89, "close": 22974.4, "volume": 14622 },
{ "date": new Date('2018-10-05T00:00:00.000Z'), "open": 22473.9, "high": 23404.75, "low": 21658.45, "close": 22601.2, "volume": 17716 },
{ "date": new Date('2018-10-12T00:00:00.000Z'), "open": 25546.96, "high": 27711.15, "low": 25227.28, "close": 26848.95, "volume": 26444 },
{ "date": new Date('2018-10-19T00:00:00.000Z'), "open": 29034.27, "high": 30285.93, "low": 28077.4, "close": 30145.37, "volume": 21129 },
{ "date": new Date('2018-10-26T00:00:00.000Z'), "open": 28144.88, "high": 30603.4, "low": 27956.49, "close": 29571.11, "volume": 25506 },
{ "date": new Date('2018-11-02T00:00:00.000Z'), "open": 26062.69, "high": 26930.44, "low": 25680.98, "close": 26237.96, "volume": 16730 },
{ "date": new Date('2018-11-09T00:00:00.000Z'), "open": 26464.34, "high": 27141.31, "low": 25952.73, "close": 26536.38, "volume": 12276 },
{ "date": new Date('2018-11-16T00:00:00.000Z'), "open": 30199.45, "high": 30806.57, "low": 28942.2, "close": 29494.06, "volume": 24850 },
{ "date": new Date('2018-11-23T00:00:00.000Z'), "open": 31186.33, "high": 31684.45, "low": 30117.28, "close": 31339.35, "volume": 13715 },
{ "date": new Date('2018-11-30T00:00:00.000Z'), "open": 28654.09, "high": 29009.33, "low": 28086.7, "close": 28397.91, "volume": 16287 },
{ "date": new Date('2018-12-07T00:00:00.000Z'), "open": 25288.78, "high": 25392.5, "low": 24880.96, "close": 25276.28, "volume": 14098 },
{ "date": new Date('2018-12-14T00:00:00.000Z'), "open": 26273.67, "high": 26393.15, "low": 25263.95, "close": 26052, "volume": 14654 },
{ "date": new Date('2018-12-21T00:00:00.000Z'), "open": 29662.4, "high": 30364.94, "low": 29068.05, "close": 29129.9, "volume": 20032 },
{ "date": new Date('2018-12-28T00:00:00.000Z'), "open": 30055.6, "high": 32285.68, "low": 29628.04, "close": 31572.57, "volume": 24649 },
{ "date": new Date('2019-01-04T00:00:00.000Z'), "open": 28368.2, "high": 29099.22, "low": 27609.62, "close": 28728.74, "volume": 16533 },
{ "date": new Date('2019-01-11T00:00:00.000Z'), "open": 26007.85, "high": 26543.08, "low": 25977.3, "close": 26122.4, "volume": 16921 },
{ "date": new Date('2019-01-18T00:00:00.000Z'), "open": 27919.6, "high": 28842.9, "low": 27781.11, "close": 28297.12, "volume": 21355 },
{ "date": new Date('2019-01-25T00:00:00.000Z'), "open": 32041.48, "high": 33264.42, "low": 30618.67, "close": 30941.5, "volume": 26209 },
{ "date": new Date('2019-02-01T00:00:00.000Z'), "open": 31116.9, "high": 33371.08, "low": 31022.8, "close": 32325.58, "volume": 29130 },
{ "date": new Date('2019-02-08T00:00:00.000Z'), "open": 28666.79, "high": 29325.01, "low": 26773.16, "close": 27857.29, "volume": 21468 },
{ "date": new Date('2019-02-15T00:00:00.000Z'), "open": 25778.05, "high": 26850.47, "low": 24764.23, "close": 26492.88, "volume": 22711 },
{ "date": new Date('2019-02-22T00:00:00.000Z'), "open": 29003.71, "high": 29168.22, "low": 27684.64, "close": 28641.35, "volume": 12661 },
{ "date": new Date('2019-03-01T00:00:00.000Z'), "open": 32078.06, "high": 32923.29, "low": 31847.44, "close": 32837.68, "volume": 23227 },
{ "date": new Date('2019-03-08T00:00:00.000Z'), "open": 32181.67, "high": 32255.19, "low": 30063.48, "close": 31214.03, "volume": 27996 },
{ "date": new Date('2019-03-15T00:00:00.000Z'), "open": 27461.31, "high": 27535.18, "low": 26347, "close": 26492.37, "volume": 20915 },
{ "date": new Date('2019-03-22T00:00:00.000Z'), "open": 25169.35, "high": 27003.26, "low": 24615.2, "close": 26054.34, "volume": 22489 },
{ "date": new Date('2019-03-29T00:00:00.000Z'), "open": 29069.25, "high": 30537.38, "low": 28594.53, "close": 29932.15, "volume": 23160 },
{ "date": new Date('2019-04-05T00:00:00.000Z'), "open": 33003.19, "high": 33636.91, "low": 32313.05, "close": 33397.26, "volume": 19321 },
{ "date": new Date('2019-04-12T00:00:00.000Z'), "open": 31918.41, "high": 33003.38, "low": 30747.09, "close": 30830.8, "volume": 23229 },
{ "date": new Date('2019-04-19T00:00:00.000Z'), "open": 27064.8, "high": 28359.86, "low": 26503.75, "close": 28184.2, "volume": 26912 },
{ "date": new Date('2019-04-26T00:00:00.000Z'), "open": 27573.58, "high": 28857.54, "low": 26852.78, "close": 28272.5, "volume": 18405 },
{ "date": new Date('2019-05-03T00:00:00.000Z'), "open": 31958.75, "high": 32150.94, "low": 30176.76, "close": 31340.84, "volume": 22364 },
{ "date": new Date('2019-05-10T00:00:00.000Z'), "open": 33888.83, "high": 33945.23, "low": 33022.23, "close": 33490.61, "volume": 18582 },
{ "date": new Date('2019-05-17T00:00:00.000Z'), "open": 31265.27, "high": 31594.88, "low": 30229.16, "close": 30852.56, "volume": 15591 },
{ "date": new Date('2019-05-24T00:00:00.000Z'), "open": 27192.9, "high": 27580.16, "low": 25921.42, "close": 26546.5, "volume": 17344 },
{ "date": new Date('2019-05-31T00:00:00.000Z'), "open": 26778.91, "high": 28903.19, "low": 25872.64, "close": 27807.05, "volume": 20654 },
{ "date": new Date('2019-06-07T00:00:00.000Z'), "open": 31645.98, "high": 32699.78, "low": 30483.48, "close": 31951.78, "volume": 13760 },
{ "date": new Date('2019-06-14T00:00:00.000Z'), "open": 33781.79, "high": 35711, "low": 32867.88, "close": 34871.18, "volume": 29898 },
{ "date": new Date('2019-06-21T00:00:00.000Z'), "open": 31880.77, "high": 31913.13, "low": 31026.46, "close": 31132.58, "volume": 23370 },
{ "date": new Date('2019-06-28T00:00:00.000Z'), "open": 27725.57, "high": 28888.33, "low": 27315.45, "close": 27867.27, "volume": 8844 },
{ "date": new Date('2019-07-05T00:00:00.000Z'), "open": 28970.36, "high": 31438.37, "low": 28012.99, "close": 30411.15, "volume": 28121 },
{ "date": new Date('2019-07-12T00:00:00.000Z'), "open": 34625.38, "high": 36209.43, "low": 33649.26, "close": 35946.73, "volume": 23161 },
{ "date": new Date('2019-07-19T00:00:00.000Z'), "open": 37085.22, "high": 38303.95, "low": 35738.77, "close": 37987.12, "volume": 25039 },
{ "date": new Date('2019-07-26T00:00:00.000Z'), "open": 34129.58, "high": 34907.17, "low": 33538.5, "close": 34332.08, "volume": 15274 },
{ "date": new Date('2019-08-02T00:00:00.000Z'), "open": 31082.96, "high": 32845.72, "low": 30551.31, "close": 31756.55, "volume": 20444 },
{ "date": new Date('2019-08-09T00:00:00.000Z'), "open": 33945.13, "high": 35479.92, "low": 32650.51, "close": 34138.22, "volume": 16685 },
{ "date": new Date('2019-08-16T00:00:00.000Z'), "open": 38654.18, "high": 40828.76, "low": 38555.7, "close": 40565.71, "volume": 34939 },
{ "date": new Date('2019-08-23T00:00:00.000Z'), "open": 40791.34, "high": 43702.34, "low": 39485, "close": 42336.54, "volume": 24874 },
{ "date": new Date('2019-08-30T00:00:00.000Z'), "open": 37543.02, "high": 37809.71, "low": 35702.26, "close": 36906.68, "volume": 20828 },
{ "date": new Date('2019-09-06T00:00:00.000Z'), "open": 34155.41, "high": 35611.5, "low": 33317.88, "close": 34645.15, "volume": 16420 },
{ "date": new Date('2019-09-13T00:00:00.000Z'), "open": 37931.96, "high": 39105.2, "low": 35990.46, "close": 37468.15, "volume": 18484 },
{ "date": new Date('2019-09-20T00:00:00.000Z'), "open": 41961.68, "high": 42090.46, "low": 39958.71, "close": 41570.61, "volume": 13805 },
{ "date": new Date('2019-09-27T00:00:00.000Z'), "open": 40735.86, "high": 42415.5, "low": 39570.93, "close": 41561.97, "volume": 22706 },
{ "date": new Date('2019-10-04T00:00:00.000Z'), "open": 36564.4, "high": 38002.5, "low": 35443.33, "close": 36429.85, "volume": 18630 },
{ "date": new Date('2019-10-11T00:00:00.000Z'), "open": 34614.53, "high": 35447, "low": 34456.1, "close": 34952.47, "volume": 12352 },
{ "date": new Date('2019-10-18T00:00:00.000Z'), "open": 38999.59, "high": 39299.41, "low": 37682.66, "close": 38461.55, "volume": 14009 },
{ "date": new Date('2019-10-25T00:00:00.000Z'), "open": 42404.63, "high": 43904.8, "low": 39507.38, "close": 41146.14, "volume": 27546 },
{ "date": new Date('2019-11-01T00:00:00.000Z'), "open": 39320.23, "high": 40221.4, "low": 37757.21, "close": 37955.7, "volume": 23751 },
{ "date": new Date('2019-11-08T00:00:00.000Z'), "open": 33319.47, "high": 34781.52, "low": 33252.8, "close": 34539.7, "volume": 26054 },
{ "date": new Date('2019-11-15T00:00:00.000Z'), "open": 33795.58, "high": 35132.97, "low": 32874.21, "close": 33911.93, "volume": 13614 },
{ "date": new Date('2019-11-22T00:00:00.000Z'), "open": 38335.03, "high": 38897, "low": 37128.51, "close": 38854.7, "volume": 21252 },
{ "date": new Date('2019-11-29T00:00:00.000Z'), "open": 42009.93, "high": 43408.94, "low": 41311.18, "close": 42255.77, "volume": 17572 },
{ "date": new Date('2019-12-06T00:00:00.000Z'), "open": 39444.4, "high": 40492.97, "low": 37810.9, "close": 38109.82, "volume": 26205 },
{ "date": new Date('2019-12-13T00:00:00.000Z'), "open": 33590.32, "high": 34293.77, "low": 33125.97, "close": 34285.46, "volume": 16984 },
{ "date": new Date('2019-12-20T00:00:00.000Z'), "open": 34589.96, "high": 35060.21, "low": 33716.7, "close": 34071.86, "volume": 12016 },
{ "date": new Date('2019-12-27T00:00:00.000Z'), "open": 38776.26, "high": 40157.11, "low": 36837.15, "close": 37873.29, "volume": 26331 },
{ "date": new Date('2020-01-03T00:00:00.000Z'), "open": 40038.57, "high": 42726.22, "low": 39634.43, "close": 42081.69, "volume": 35935 },
{ "date": new Date('2020-01-10T00:00:00.000Z'), "open": 38469.9, "high": 39507.2, "low": 36708.25, "close": 37722.5, "volume": 20910 },
{ "date": new Date('2020-01-17T00:00:00.000Z'), "open": 33596.19, "high": 34458, "low": 32836.06, "close": 34399.54, "volume": 20560 },
{ "date": new Date('2020-01-24T00:00:00.000Z'), "open": 35765.5, "high": 36663.68, "low": 34453.85, "close": 36475.68, "volume": 13880 },
{ "date": new Date('2020-01-31T00:00:00.000Z'), "open": 41529.85, "high": 42015.01, "low": 40121.71, "close": 40277.57, "volume": 21480 },
{ "date": new Date('2020-02-07T00:00:00.000Z'), "open": 41548.93, "high": 43274.04, "low": 40442, "close": 41827.28, "volume": 13049 },
{ "date": new Date('2020-02-14T00:00:00.000Z'), "open": 37577.4, "high": 39773.43, "low": 37344, "close": 38857.35, "volume": 19397 },
{ "date": new Date('2020-02-21T00:00:00.000Z'), "open": 35182.76, "high": 35981.75, "low": 33181.6, "close": 34076.43, "volume": 23689 },
{ "date": new Date('2020-02-28T00:00:00.000Z'), "open": 36428.79, "high": 37189.08, "low": 34258.1, "close": 35183.48, "volume": 20138 },
{ "date": new Date('2020-03-06T00:00:00.000Z'), "open": 39836.34, "high": 42607.24, "low": 38398.84, "close": 41324, "volume": 20466 },
{ "date": new Date('2020-03-13T00:00:00.000Z'), "open": 41549.5, "high": 42823.8, "low": 40203.74, "close": 41540.44, "volume": 15006 },
{ "date": new Date('2020-03-20T00:00:00.000Z'), "open": 36835.45, "high": 39190.12, "low": 36262.89, "close": 38372.15, "volume": 22696 },
{ "date": new Date('2020-03-27T00:00:00.000Z'), "open": 35515.18, "high": 36300.79, "low": 33522.43, "close": 34836.61, "volume": 14113 },
{ "date": new Date('2020-04-03T00:00:00.000Z'), "open": 38144.97, "high": 41398.7, "low": 37286.73, "close": 40056.11, "volume": 28778 },
{ "date": new Date('2020-04-10T00:00:00.000Z'), "open": 44857.54, "high": 46095.9, "low": 43164.76, "close": 43958.92, "volume": 24802 },
{ "date": new Date('2020-04-17T00:00:00.000Z'), "open": 43071.7, "high": 43434.77, "low": 41622.93, "close": 43390.4, "volume": 20976 },
{ "date": new Date('2020-04-24T00:00:00.000Z'), "open": 38172.17, "high": 39435.08, "low": 36744.64, "close": 37158.05, "volume": 15754 },
{ "date": new Date('2020-05-01T00:00:00.000Z'), "open": 35310.52, "high": 37219.81, "low": 34390.85, "close": 36026.12, "volume": 13677 },
{ "date": new Date('2020-05-08T00:00:00.000Z'), "open": 40200.21, "high": 41977.71, "low": 38847.02, "close": 40849.35, "volume": 22178 },
{ "date": new Date('2020-05-15T00:00:00.000Z'), "open": 45033.95, "high": 48307.6, "low": 44941.89, "close": 46585.25, "volume": 28398 },
{ "date": new Date('2020-05-22T00:00:00.000Z'), "open": 44513.52, "high": 45078.96, "low": 42595.97, "close": 43989, "volume": 20966 },
{ "date": new Date('2020-05-29T00:00:00.000Z'), "open": 38616, "high": 39043.31, "low": 38310.53, "close": 38694.49, "volume": 17009 },
{ "date": new Date('2020-06-05T00:00:00.000Z'), "open": 37865.56, "high": 39778.48, "low": 36659.39, "close": 38302.39, "volume": 11131 },
{ "date": new Date('2020-06-12T00:00:00.000Z'), "open": 43299.88, "high": 44991.99, "low": 41226.45, "close": 42949.34, "volume": 21044 },
{ "date": new Date('2020-06-19T00:00:00.000Z'), "open": 46433.06, "high": 48709.02, "low": 45129.64, "close": 47006.47, "volume": 19002 },
{ "date": new Date('2020-06-26T00:00:00.000Z'), "open": 43875.01, "high": 46720.43, "low": 43076.36, "close": 45153.05, "volume": 18540 },
{ "date": new Date('2020-07-03T00:00:00.000Z'), "open": 39799.46, "high": 40687.78, "low": 39547.47, "close": 39684.67, "volume": 9875 },
{ "date": new Date('2020-07-10T00:00:00.000Z'), "open": 40042.15, "high": 41082.91, "low": 39000.45, "close": 40782.55, "volume": 20314 },
{ "date": new Date('2020-07-17T00:00:00.000Z'), "open": 46414.19, "high": 47890.36, "low": 44477.65, "close": 45145.69, "volume": 24284 },
{ "date": new Date('2020-07-24T00:00:00.000Z'), "open": 47722.12, "high": 48563.57, "low": 47254.52, "close": 48481.8, "volume": 19972 },
{ "date": new Date('2020-07-31T00:00:00.000Z'), "open": 44317.2, "high": 45303.18, "low": 42067.98, "close": 43037.51, "volume": 27030 },
{ "date": new Date('2020-08-07T00:00:00.000Z'), "open": 38331.93, "high": 38432.14, "low": 36049.48, "close": 37103.13, "volume": 23308 },
{ "date": new Date('2020-08-14T00:00:00.000Z'), "open": 38581.05, "high": 39121.4, "low": 37531.53, "close": 38501.92, "volume": 10575 },
{ "date": new Date('2020-08-21T00:00:00.000Z'), "open": 43836.38, "high": 45389.48, "low": 43004.21, "close": 45314.73, "volume": 20136 },
{ "date": new Date('2020-08-28T00:00:00.000Z'), "open": 46740.26, "high": 48514.9, "low": 46391.77, "close": 48455.63, "volume": 29478 },
{ "date": new Date('2020-09-04T00:00:00.000Z'), "open": 43529.54, "high": 44934.58, "low": 42227.73, "close": 43823.57, "volume": 12767 },
{ "date": new Date('2020-09-11T00:00:00.000Z'), "open": 39682.49, "high": 40809.15, "low": 38915.73, "close": 40303.85, "volume": 17427 },
{ "date": new Date('2020-09-18T00:00:00.000Z'), "open": 43090.71, "high": 44475.27, "low": 41756.58, "close": 41881.46, "volume": 16111 },
{ "date": new Date('2020-09-25T00:00:00.000Z'), "open": 47418.47, "high": 49914.51, "low": 45730.39, "close": 48503.1, "volume": 21310 },
{ "date": new Date('2020-10-02T00:00:00.000Z'), "open": 48762.6, "high": 49509.92, "low": 47384.82, "close": 47945.79, "volume": 17542 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per period: its open, high, low, close, and optionally volume.
const candles = [
{ date: new Date('2026-08-20'), open: 243.1, high: 246.4, low: 241.8, close: 245.2, volume: 2410000 },
{ date: new Date('2026-08-21'), open: 245.2, high: 247.0, low: 243.9, close: 244.6, volume: 1980000 },
];
```
Each row needs a low at or below its open and close, and a high at or above them; Lilt throws on a candle that breaks that rule rather than drawing it wrong. The headline is the latest close and the chip is the change from the first open to the last close. A rising candle (close at or above open) takes `--lilt-candle-up`, a falling one `--lilt-candle-down`; both follow your positive and negative tokens. Every candle draws into a handful of paths, so years of history stay fast.
### Period select
```tsx
```
### Hover
Hover a candle to move the headline to its close and read its open, high and low beside the date. The crosshair runs through the volume pane too, and hover there reads the same day.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `data` (`Row[]`): One row per x position. Omit when using ranges.
- `x` (`key of Row`): Text, number, or Date field for the x axis.
- `open` (`key of Row`): Numeric field holding each period’s open.
- `high` (`key of Row`): Numeric field holding each period’s high.
- `low` (`key of Row`): Numeric field holding each period’s low.
- `close` (`key of Row`): Numeric field holding each period’s close. Drives the headline and pills.
- `volume` (`key of Row`): Numeric field holding traded volume, drawn as a linked pane colored by direction.
- `display` (`'candle' | 'hollow' | 'ohlc' | 'area'`): Filled candles (default), hollow rising bodies, OHLC bars, or an area of the close colored by direction.
- `scale` (`'linear' | 'log'`): Log spaces prices by ratio, so a doubling looks the same at any level.
- `label` (`string`): Names the price in hover. Defaults to Price.
- `live` (`boolean`): Follow the newest candle as rows arrive, with a control to return to it.
- `volumeHeight` (`number`): Height of the volume pane in pixels. Defaults to 64.
- `depth` (`boolean`): Draws each body as a solid block whose front spans exactly open to close. OHLC bars and the area stay flat.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `delta` (`number`): Fractional change for the chip: 0.082 shows +8.2%.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label in the header.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the data.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): False removes the legend without changing the data. How the legend under the plot lays out: value tiles (default), a compact inline key, list rows, tinted pills, or bars that also draw each value against the largest.
- `legendSwatch` (`'square' | 'dot' | 'line'`): The mark beside each legend label. Defaults to a rounded square.
- `height` (`number`): Plot height in pixels. Defaults to 240.
- `axis` (`'minimal' | 'dots' | 'inline' | 'ruler' | 'classic' | 'segmented' | { x, y }`): Axis preset. Minimal (default) labels only the x ends and has no grid. Set one per axis with `{ x, y }`; a segmented axis can take a `gradient` to read as a range.
- `hover` (`'pills' | 'tooltip' | 'strip' | 'headline'`): The one readout for the hovered point: pills on the axes (default), a tooltip with every series, a strip docked above the plot, or the headline and tiles alone.
- `hoverStyle` (`'soft' | 'solid' | 'accent'`): How the pills or tooltip look. Soft (default) is surface glass; accent tints it with the hovered series.
- `pillPosition` (`'auto' | 'mark' | 'axis'`): Where the value pill sits: above the hovered mark, or on the y axis. Auto picks mark when there are no y labels.
- `tooltipIndicator` (`'square' | 'dot' | 'line'`): Series marker on each tooltip row, with hover="tooltip". Square by default.
- `background` (`'dots' | 'grid' | 'lines' | 'none'`): Texture behind the marks. Dots by default, with a hover spotlight.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `axisInset` (`number`): Padding between the plot edges and axis labels or pills.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `compare` (`boolean | 'headline' | 'badge'`): Drag across the plot to compare two points in time. True or headline reads the change in the headline; badge reads it in the card’s tab and leaves the headline at rest.
- `sync` (`string`): Link hover and pins with every card that uses the same name, matched by x value. A click pins them all, with a ghost pin on the others; Alt-click pins one card only.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `formatAxisValue` (`(value: number) => string`): Custom compact axis value text.
- `formatX` (`(value: string | number | Date) => string`): Custom x label text.
- `xType` (`'category' | 'number' | 'time'`): Override inferred x type. Use time for numeric Unix timestamps in milliseconds.
- `spotlight` (`boolean`): Highlight the inspected position in the plot background. Defaults to true.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
- `pillValue` (`'series' | 'stack'`): Read an individual series value (default) or its stacked height. Has no effect when the card has no stacked series.
- `decimate` (`boolean`): Defaults to true. Line and Area marks retain at most four observations per pixel column. Other marks draw every row; inspection and summaries always read the full data.
- `headline` (`number`): Override the resting headline; an active range headline takes precedence.
## Indicator chart: `IndicatorChartCard`
Price on top and oscillators underneath, all reading the same day as you hover. Docs: https://liltui.vercel.app/finance/indicator
```tsx
import { IndicatorChartCard } from '@lilt-ui/charts/finance';
```
### Complete examples
#### Indicator card
```tsx
'use client';
import { IndicatorChartCard } from '@lilt-ui/charts/finance';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "1m", "label": "1M", "data": [
{ "date": new Date('2026-08-27T00:00:00.000Z'), "open": 190.78, "high": 196.36, "low": 190.07, "close": 193.85, "volume": 2686171 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "open": 193.85, "high": 197.11, "low": 192.05, "close": 194.2, "volume": 2566984 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "open": 194.2, "high": 194.38, "low": 191.92, "close": 192.45, "volume": 2585676 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "open": 192.45, "high": 192.6, "low": 190.83, "close": 191.48, "volume": 2902453 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "open": 191.48, "high": 195.18, "low": 190.07, "close": 194.15, "volume": 2226035 },
{ "date": new Date('2026-09-01T00:00:00.000Z'), "open": 194.15, "high": 194.96, "low": 191.2, "close": 194.68, "volume": 2865378 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "open": 194.68, "high": 195.97, "low": 191.95, "close": 192.18, "volume": 3179562 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "open": 192.18, "high": 197.54, "low": 190.1, "close": 195.29, "volume": 2203328 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "open": 195.29, "high": 200.11, "low": 193.34, "close": 197.72, "volume": 3287887 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "open": 197.72, "high": 202.47, "low": 196.55, "close": 200.86, "volume": 2108982 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "open": 200.86, "high": 202.44, "low": 200.14, "close": 201.7, "volume": 3050788 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "open": 201.7, "high": 206.09, "low": 201.08, "close": 203.76, "volume": 3160303 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "open": 203.76, "high": 205.09, "low": 203.28, "close": 203.62, "volume": 1547552 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "open": 203.62, "high": 206.45, "low": 199.93, "close": 200.54, "volume": 2419421 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "open": 200.54, "high": 203.41, "low": 196.4, "close": 199.31, "volume": 2137922 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "open": 199.31, "high": 201.44, "low": 197.01, "close": 197.94, "volume": 2856143 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "open": 197.94, "high": 200.87, "low": 193.01, "close": 195.54, "volume": 2016849 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "open": 195.54, "high": 197.51, "low": 192.95, "close": 196.79, "volume": 2621817 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "open": 196.79, "high": 199.2, "low": 194.82, "close": 197.52, "volume": 3033046 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "open": 197.52, "high": 203.69, "low": 197, "close": 200.66, "volume": 3041051 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "open": 200.66, "high": 204.11, "low": 198.61, "close": 203.59, "volume": 2082501 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "open": 203.59, "high": 208.28, "low": 201.87, "close": 205.27, "volume": 3222974 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "open": 205.27, "high": 206.64, "low": 203, "close": 203.49, "volume": 2462821 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "open": 203.49, "high": 204.33, "low": 198.71, "close": 200.51, "volume": 2368043 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "open": 200.51, "high": 204.21, "low": 199.53, "close": 204.04, "volume": 2964809 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "open": 204.04, "high": 205.6, "low": 199.82, "close": 201.65, "volume": 3263425 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "open": 201.65, "high": 206.26, "low": 198.81, "close": 203.2, "volume": 3180001 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "open": 203.2, "high": 206.48, "low": 200.12, "close": 205.46, "volume": 2041039 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "open": 205.46, "high": 208.24, "low": 202.34, "close": 203.24, "volume": 2468141 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "open": 203.24, "high": 206, "low": 202.82, "close": 205.56, "volume": 2886985 },
] },
{ "id": "3m", "label": "3M", "data": [
{ "date": new Date('2026-06-28T00:00:00.000Z'), "open": 175.33, "high": 180.25, "low": 174.18, "close": 178.33, "volume": 3702584 },
{ "date": new Date('2026-06-29T00:00:00.000Z'), "open": 178.33, "high": 178.83, "low": 175.83, "close": 176.69, "volume": 2561676 },
{ "date": new Date('2026-06-30T00:00:00.000Z'), "open": 176.69, "high": 178.45, "low": 175.77, "close": 176.71, "volume": 1691710 },
{ "date": new Date('2026-07-01T00:00:00.000Z'), "open": 176.71, "high": 177.68, "low": 174.58, "close": 175.69, "volume": 1891064 },
{ "date": new Date('2026-07-02T00:00:00.000Z'), "open": 175.69, "high": 176.87, "low": 172.86, "close": 175.31, "volume": 1862025 },
{ "date": new Date('2026-07-03T00:00:00.000Z'), "open": 175.31, "high": 178.66, "low": 173.7, "close": 178.41, "volume": 2873801 },
{ "date": new Date('2026-07-04T00:00:00.000Z'), "open": 178.41, "high": 181.32, "low": 176.93, "close": 179.67, "volume": 2917261 },
{ "date": new Date('2026-07-05T00:00:00.000Z'), "open": 179.67, "high": 182.32, "low": 176.74, "close": 178.41, "volume": 1924836 },
{ "date": new Date('2026-07-06T00:00:00.000Z'), "open": 178.41, "high": 182.22, "low": 175.89, "close": 181.04, "volume": 2601632 },
{ "date": new Date('2026-07-07T00:00:00.000Z'), "open": 181.04, "high": 181.73, "low": 177.68, "close": 178.74, "volume": 2747583 },
{ "date": new Date('2026-07-08T00:00:00.000Z'), "open": 178.74, "high": 180.38, "low": 176.15, "close": 180.24, "volume": 1829364 },
{ "date": new Date('2026-07-09T00:00:00.000Z'), "open": 180.24, "high": 181.75, "low": 176.53, "close": 178.88, "volume": 2875169 },
{ "date": new Date('2026-07-10T00:00:00.000Z'), "open": 178.88, "high": 180.17, "low": 178.39, "close": 180.16, "volume": 1771891 },
{ "date": new Date('2026-07-11T00:00:00.000Z'), "open": 180.16, "high": 182.25, "low": 178.11, "close": 178.34, "volume": 1760700 },
{ "date": new Date('2026-07-12T00:00:00.000Z'), "open": 178.34, "high": 183.67, "low": 175.68, "close": 181.53, "volume": 2986133 },
{ "date": new Date('2026-07-13T00:00:00.000Z'), "open": 181.53, "high": 183.06, "low": 178.25, "close": 180.7, "volume": 2754332 },
{ "date": new Date('2026-07-14T00:00:00.000Z'), "open": 180.7, "high": 182.04, "low": 178.8, "close": 181.02, "volume": 2853710 },
{ "date": new Date('2026-07-15T00:00:00.000Z'), "open": 181.02, "high": 184.6, "low": 178.5, "close": 182.81, "volume": 3309967 },
{ "date": new Date('2026-07-16T00:00:00.000Z'), "open": 182.81, "high": 187.85, "low": 180.39, "close": 185.86, "volume": 2219317 },
{ "date": new Date('2026-07-17T00:00:00.000Z'), "open": 185.86, "high": 186.1, "low": 181.67, "close": 184.07, "volume": 2014204 },
{ "date": new Date('2026-07-18T00:00:00.000Z'), "open": 184.07, "high": 185.04, "low": 180.87, "close": 182.15, "volume": 2597964 },
{ "date": new Date('2026-07-19T00:00:00.000Z'), "open": 182.15, "high": 185.62, "low": 181.28, "close": 182.95, "volume": 1855149 },
{ "date": new Date('2026-07-20T00:00:00.000Z'), "open": 182.95, "high": 184.31, "low": 179.38, "close": 180.08, "volume": 3538359 },
{ "date": new Date('2026-07-21T00:00:00.000Z'), "open": 180.08, "high": 183.87, "low": 178.35, "close": 182.21, "volume": 2111130 },
{ "date": new Date('2026-07-22T00:00:00.000Z'), "open": 182.21, "high": 183.77, "low": 179.79, "close": 182.59, "volume": 2470964 },
{ "date": new Date('2026-07-23T00:00:00.000Z'), "open": 182.59, "high": 185.11, "low": 178.74, "close": 180, "volume": 2215306 },
{ "date": new Date('2026-07-24T00:00:00.000Z'), "open": 180, "high": 182.37, "low": 179.22, "close": 181.3, "volume": 1930100 },
{ "date": new Date('2026-07-25T00:00:00.000Z'), "open": 181.3, "high": 182.29, "low": 176.78, "close": 179.41, "volume": 2564712 },
{ "date": new Date('2026-07-26T00:00:00.000Z'), "open": 179.41, "high": 181.57, "low": 176.8, "close": 179.78, "volume": 2695389 },
{ "date": new Date('2026-07-27T00:00:00.000Z'), "open": 179.78, "high": 183.37, "low": 177.65, "close": 182.53, "volume": 2612169 },
{ "date": new Date('2026-07-28T00:00:00.000Z'), "open": 182.53, "high": 185.98, "low": 180.64, "close": 185.06, "volume": 2871046 },
{ "date": new Date('2026-07-29T00:00:00.000Z'), "open": 185.06, "high": 185.86, "low": 180.35, "close": 182.69, "volume": 1950375 },
{ "date": new Date('2026-07-30T00:00:00.000Z'), "open": 182.69, "high": 185.15, "low": 177.55, "close": 180.14, "volume": 3537483 },
{ "date": new Date('2026-07-31T00:00:00.000Z'), "open": 180.14, "high": 180.56, "low": 178.7, "close": 179.29, "volume": 3027806 },
{ "date": new Date('2026-08-01T00:00:00.000Z'), "open": 179.29, "high": 183.63, "low": 178.43, "close": 181.63, "volume": 2848629 },
{ "date": new Date('2026-08-02T00:00:00.000Z'), "open": 181.63, "high": 185.46, "low": 179.23, "close": 182.99, "volume": 2719123 },
{ "date": new Date('2026-08-03T00:00:00.000Z'), "open": 182.99, "high": 183.03, "low": 181.76, "close": 181.94, "volume": 2892428 },
{ "date": new Date('2026-08-04T00:00:00.000Z'), "open": 181.94, "high": 184.62, "low": 181.8, "close": 182.87, "volume": 3059787 },
{ "date": new Date('2026-08-05T00:00:00.000Z'), "open": 182.87, "high": 183.86, "low": 179.61, "close": 180.65, "volume": 3153744 },
{ "date": new Date('2026-08-06T00:00:00.000Z'), "open": 180.65, "high": 183.48, "low": 180.36, "close": 183.38, "volume": 2096144 },
{ "date": new Date('2026-08-07T00:00:00.000Z'), "open": 183.38, "high": 183.72, "low": 179.24, "close": 181.35, "volume": 2428129 },
{ "date": new Date('2026-08-08T00:00:00.000Z'), "open": 181.35, "high": 183.15, "low": 178.87, "close": 181.68, "volume": 1957201 },
{ "date": new Date('2026-08-09T00:00:00.000Z'), "open": 181.68, "high": 184.48, "low": 180.15, "close": 184.09, "volume": 3131278 },
{ "date": new Date('2026-08-10T00:00:00.000Z'), "open": 184.09, "high": 187.25, "low": 182.16, "close": 184.76, "volume": 1986018 },
{ "date": new Date('2026-08-11T00:00:00.000Z'), "open": 184.76, "high": 185.27, "low": 181.34, "close": 184.06, "volume": 2629438 },
{ "date": new Date('2026-08-12T00:00:00.000Z'), "open": 184.06, "high": 185.48, "low": 181.89, "close": 182.38, "volume": 2086285 },
{ "date": new Date('2026-08-13T00:00:00.000Z'), "open": 182.38, "high": 185.11, "low": 180.61, "close": 183.66, "volume": 2860446 },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "open": 183.66, "high": 184.63, "low": 180.29, "close": 181.67, "volume": 2398495 },
{ "date": new Date('2026-08-15T00:00:00.000Z'), "open": 181.67, "high": 185.05, "low": 179.28, "close": 184.46, "volume": 2448935 },
{ "date": new Date('2026-08-16T00:00:00.000Z'), "open": 184.46, "high": 187.8, "low": 182.88, "close": 186.13, "volume": 2425201 },
{ "date": new Date('2026-08-17T00:00:00.000Z'), "open": 186.13, "high": 188.94, "low": 184.01, "close": 184.01, "volume": 2897024 },
{ "date": new Date('2026-08-18T00:00:00.000Z'), "open": 184.01, "high": 185.14, "low": 181.96, "close": 185.05, "volume": 2346585 },
{ "date": new Date('2026-08-19T00:00:00.000Z'), "open": 185.05, "high": 187.56, "low": 181.6, "close": 183.2, "volume": 1782162 },
{ "date": new Date('2026-08-20T00:00:00.000Z'), "open": 183.2, "high": 183.37, "low": 181.1, "close": 182.24, "volume": 3222334 },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "open": 182.24, "high": 187.12, "low": 180.33, "close": 184.51, "volume": 2058942 },
{ "date": new Date('2026-08-22T00:00:00.000Z'), "open": 184.51, "high": 187.36, "low": 184.49, "close": 186.44, "volume": 1849602 },
{ "date": new Date('2026-08-23T00:00:00.000Z'), "open": 186.44, "high": 189.61, "low": 183.73, "close": 188.9, "volume": 1968815 },
{ "date": new Date('2026-08-24T00:00:00.000Z'), "open": 188.9, "high": 192.67, "low": 188.31, "close": 191.85, "volume": 3047593 },
{ "date": new Date('2026-08-25T00:00:00.000Z'), "open": 191.85, "high": 194.69, "low": 188.25, "close": 190.53, "volume": 1890866 },
{ "date": new Date('2026-08-26T00:00:00.000Z'), "open": 190.53, "high": 192.03, "low": 188.23, "close": 190.78, "volume": 1826419 },
{ "date": new Date('2026-08-27T00:00:00.000Z'), "open": 190.78, "high": 196.36, "low": 190.07, "close": 193.85, "volume": 2686171 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "open": 193.85, "high": 197.11, "low": 192.05, "close": 194.2, "volume": 2566984 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "open": 194.2, "high": 194.38, "low": 191.92, "close": 192.45, "volume": 2585676 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "open": 192.45, "high": 192.6, "low": 190.83, "close": 191.48, "volume": 2902453 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "open": 191.48, "high": 195.18, "low": 190.07, "close": 194.15, "volume": 2226035 },
{ "date": new Date('2026-09-01T00:00:00.000Z'), "open": 194.15, "high": 194.96, "low": 191.2, "close": 194.68, "volume": 2865378 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "open": 194.68, "high": 195.97, "low": 191.95, "close": 192.18, "volume": 3179562 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "open": 192.18, "high": 197.54, "low": 190.1, "close": 195.29, "volume": 2203328 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "open": 195.29, "high": 200.11, "low": 193.34, "close": 197.72, "volume": 3287887 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "open": 197.72, "high": 202.47, "low": 196.55, "close": 200.86, "volume": 2108982 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "open": 200.86, "high": 202.44, "low": 200.14, "close": 201.7, "volume": 3050788 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "open": 201.7, "high": 206.09, "low": 201.08, "close": 203.76, "volume": 3160303 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "open": 203.76, "high": 205.09, "low": 203.28, "close": 203.62, "volume": 1547552 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "open": 203.62, "high": 206.45, "low": 199.93, "close": 200.54, "volume": 2419421 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "open": 200.54, "high": 203.41, "low": 196.4, "close": 199.31, "volume": 2137922 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "open": 199.31, "high": 201.44, "low": 197.01, "close": 197.94, "volume": 2856143 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "open": 197.94, "high": 200.87, "low": 193.01, "close": 195.54, "volume": 2016849 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "open": 195.54, "high": 197.51, "low": 192.95, "close": 196.79, "volume": 2621817 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "open": 196.79, "high": 199.2, "low": 194.82, "close": 197.52, "volume": 3033046 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "open": 197.52, "high": 203.69, "low": 197, "close": 200.66, "volume": 3041051 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "open": 200.66, "high": 204.11, "low": 198.61, "close": 203.59, "volume": 2082501 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "open": 203.59, "high": 208.28, "low": 201.87, "close": 205.27, "volume": 3222974 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "open": 205.27, "high": 206.64, "low": 203, "close": 203.49, "volume": 2462821 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "open": 203.49, "high": 204.33, "low": 198.71, "close": 200.51, "volume": 2368043 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "open": 200.51, "high": 204.21, "low": 199.53, "close": 204.04, "volume": 2964809 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "open": 204.04, "high": 205.6, "low": 199.82, "close": 201.65, "volume": 3263425 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "open": 201.65, "high": 206.26, "low": 198.81, "close": 203.2, "volume": 3180001 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "open": 203.2, "high": 206.48, "low": 200.12, "close": 205.46, "volume": 2041039 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "open": 205.46, "high": 208.24, "low": 202.34, "close": 203.24, "volume": 2468141 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "open": 203.24, "high": 206, "low": 202.82, "close": 205.56, "volume": 2886985 },
] },
{ "id": "6m", "label": "6M", "data": [
{ "date": new Date('2026-03-28T00:00:00.000Z'), "open": 145.73, "high": 148.07, "low": 145.41, "close": 147.17, "volume": 2899898 },
{ "date": new Date('2026-03-29T00:00:00.000Z'), "open": 147.17, "high": 151.54, "low": 146.53, "close": 149.83, "volume": 2585536 },
{ "date": new Date('2026-03-30T00:00:00.000Z'), "open": 149.83, "high": 150.65, "low": 146.57, "close": 148.2, "volume": 1801152 },
{ "date": new Date('2026-03-31T00:00:00.000Z'), "open": 148.2, "high": 148.77, "low": 146.89, "close": 148.5, "volume": 2870322 },
{ "date": new Date('2026-04-01T00:00:00.000Z'), "open": 148.5, "high": 153.27, "low": 147.82, "close": 151.01, "volume": 3444678 },
{ "date": new Date('2026-04-02T00:00:00.000Z'), "open": 151.01, "high": 152.29, "low": 148.98, "close": 151.21, "volume": 1561281 },
{ "date": new Date('2026-04-03T00:00:00.000Z'), "open": 151.21, "high": 154.03, "low": 149.25, "close": 152.63, "volume": 2220081 },
{ "date": new Date('2026-04-04T00:00:00.000Z'), "open": 152.63, "high": 152.79, "low": 149.52, "close": 151.13, "volume": 2781695 },
{ "date": new Date('2026-04-05T00:00:00.000Z'), "open": 151.13, "high": 154.6, "low": 150.87, "close": 153.81, "volume": 2867194 },
{ "date": new Date('2026-04-06T00:00:00.000Z'), "open": 153.81, "high": 157.44, "low": 152.33, "close": 156.09, "volume": 3444996 },
{ "date": new Date('2026-04-07T00:00:00.000Z'), "open": 156.09, "high": 156.68, "low": 154.82, "close": 156.57, "volume": 1744423 },
{ "date": new Date('2026-04-08T00:00:00.000Z'), "open": 156.57, "high": 157.78, "low": 153.72, "close": 155.24, "volume": 2450699 },
{ "date": new Date('2026-04-09T00:00:00.000Z'), "open": 155.24, "high": 155.25, "low": 152.91, "close": 153.65, "volume": 1987237 },
{ "date": new Date('2026-04-10T00:00:00.000Z'), "open": 153.65, "high": 156.22, "low": 152.27, "close": 154.39, "volume": 1666324 },
{ "date": new Date('2026-04-11T00:00:00.000Z'), "open": 154.39, "high": 155.51, "low": 153.82, "close": 155.36, "volume": 2021039 },
{ "date": new Date('2026-04-12T00:00:00.000Z'), "open": 155.36, "high": 155.75, "low": 155.11, "close": 155.29, "volume": 2937036 },
{ "date": new Date('2026-04-13T00:00:00.000Z'), "open": 155.29, "high": 155.56, "low": 151.57, "close": 153.7, "volume": 1996865 },
{ "date": new Date('2026-04-14T00:00:00.000Z'), "open": 153.7, "high": 156.04, "low": 151.32, "close": 151.8, "volume": 2238815 },
{ "date": new Date('2026-04-15T00:00:00.000Z'), "open": 151.8, "high": 155.39, "low": 150.25, "close": 153.74, "volume": 3217911 },
{ "date": new Date('2026-04-16T00:00:00.000Z'), "open": 153.74, "high": 157.57, "low": 151.84, "close": 155.24, "volume": 2119930 },
{ "date": new Date('2026-04-17T00:00:00.000Z'), "open": 155.24, "high": 156.06, "low": 152.91, "close": 154.93, "volume": 1760989 },
{ "date": new Date('2026-04-18T00:00:00.000Z'), "open": 154.93, "high": 156.61, "low": 151.45, "close": 152.56, "volume": 2411306 },
{ "date": new Date('2026-04-19T00:00:00.000Z'), "open": 152.56, "high": 153.69, "low": 148.84, "close": 150.35, "volume": 2106919 },
{ "date": new Date('2026-04-20T00:00:00.000Z'), "open": 150.35, "high": 153.5, "low": 150.2, "close": 152.49, "volume": 2449872 },
{ "date": new Date('2026-04-21T00:00:00.000Z'), "open": 152.49, "high": 154.63, "low": 150.52, "close": 150.85, "volume": 2773442 },
{ "date": new Date('2026-04-22T00:00:00.000Z'), "open": 150.85, "high": 152.73, "low": 148.78, "close": 150.74, "volume": 1461180 },
{ "date": new Date('2026-04-23T00:00:00.000Z'), "open": 150.74, "high": 153.37, "low": 149.77, "close": 153.34, "volume": 3687707 },
{ "date": new Date('2026-04-24T00:00:00.000Z'), "open": 153.34, "high": 153.34, "low": 150.12, "close": 152.09, "volume": 2527334 },
{ "date": new Date('2026-04-25T00:00:00.000Z'), "open": 152.09, "high": 153.71, "low": 150.52, "close": 152.37, "volume": 1983212 },
{ "date": new Date('2026-04-26T00:00:00.000Z'), "open": 152.37, "high": 154.61, "low": 150.07, "close": 152.73, "volume": 2228479 },
{ "date": new Date('2026-04-27T00:00:00.000Z'), "open": 152.73, "high": 156.76, "low": 152.42, "close": 154.44, "volume": 2173658 },
{ "date": new Date('2026-04-28T00:00:00.000Z'), "open": 154.44, "high": 155.74, "low": 152.48, "close": 155.66, "volume": 2669832 },
{ "date": new Date('2026-04-29T00:00:00.000Z'), "open": 155.66, "high": 158.19, "low": 154.64, "close": 156.77, "volume": 3039806 },
{ "date": new Date('2026-04-30T00:00:00.000Z'), "open": 156.77, "high": 160.39, "low": 154.5, "close": 159.22, "volume": 2032129 },
{ "date": new Date('2026-05-01T00:00:00.000Z'), "open": 159.22, "high": 159.61, "low": 156.08, "close": 157.01, "volume": 3142221 },
{ "date": new Date('2026-05-02T00:00:00.000Z'), "open": 157.01, "high": 157.59, "low": 154.3, "close": 155.92, "volume": 2751851 },
{ "date": new Date('2026-05-03T00:00:00.000Z'), "open": 155.92, "high": 159.53, "low": 153.9, "close": 158.46, "volume": 2063295 },
{ "date": new Date('2026-05-04T00:00:00.000Z'), "open": 158.46, "high": 161.28, "low": 157.89, "close": 160.86, "volume": 3193688 },
{ "date": new Date('2026-05-05T00:00:00.000Z'), "open": 160.86, "high": 163.29, "low": 158.21, "close": 160.34, "volume": 2776757 },
{ "date": new Date('2026-05-06T00:00:00.000Z'), "open": 160.34, "high": 162.91, "low": 158.24, "close": 160.84, "volume": 1530875 },
{ "date": new Date('2026-05-07T00:00:00.000Z'), "open": 160.84, "high": 165.76, "low": 159.81, "close": 163.66, "volume": 3272444 },
{ "date": new Date('2026-05-08T00:00:00.000Z'), "open": 163.66, "high": 167.1, "low": 162.88, "close": 165, "volume": 2914948 },
{ "date": new Date('2026-05-09T00:00:00.000Z'), "open": 165, "high": 166.61, "low": 163.64, "close": 164.19, "volume": 2912552 },
{ "date": new Date('2026-05-10T00:00:00.000Z'), "open": 164.19, "high": 166.67, "low": 162.65, "close": 162.88, "volume": 1857223 },
{ "date": new Date('2026-05-11T00:00:00.000Z'), "open": 162.88, "high": 163.4, "low": 161.22, "close": 163.06, "volume": 2688559 },
{ "date": new Date('2026-05-12T00:00:00.000Z'), "open": 163.06, "high": 167.26, "low": 161.86, "close": 164.94, "volume": 3262744 },
{ "date": new Date('2026-05-13T00:00:00.000Z'), "open": 164.94, "high": 169.28, "low": 163.15, "close": 167.47, "volume": 2715268 },
{ "date": new Date('2026-05-14T00:00:00.000Z'), "open": 167.47, "high": 169.14, "low": 166.23, "close": 167.62, "volume": 2496159 },
{ "date": new Date('2026-05-15T00:00:00.000Z'), "open": 167.62, "high": 169.78, "low": 166.89, "close": 169.28, "volume": 2835271 },
{ "date": new Date('2026-05-16T00:00:00.000Z'), "open": 169.28, "high": 170.41, "low": 166.83, "close": 168.98, "volume": 1851239 },
{ "date": new Date('2026-05-17T00:00:00.000Z'), "open": 168.98, "high": 172.53, "low": 167.83, "close": 170.99, "volume": 2175470 },
{ "date": new Date('2026-05-18T00:00:00.000Z'), "open": 170.99, "high": 173.45, "low": 168.74, "close": 169.09, "volume": 2317336 },
{ "date": new Date('2026-05-19T00:00:00.000Z'), "open": 169.09, "high": 172.51, "low": 166.85, "close": 170.96, "volume": 2279714 },
{ "date": new Date('2026-05-20T00:00:00.000Z'), "open": 170.96, "high": 173.64, "low": 169.41, "close": 171.33, "volume": 2598995 },
{ "date": new Date('2026-05-21T00:00:00.000Z'), "open": 171.33, "high": 173.01, "low": 169.05, "close": 170, "volume": 1941274 },
{ "date": new Date('2026-05-22T00:00:00.000Z'), "open": 170, "high": 170.87, "low": 167.4, "close": 170.01, "volume": 2223511 },
{ "date": new Date('2026-05-23T00:00:00.000Z'), "open": 170.01, "high": 170.91, "low": 166.5, "close": 168.73, "volume": 2776761 },
{ "date": new Date('2026-05-24T00:00:00.000Z'), "open": 168.73, "high": 169.99, "low": 166.96, "close": 167.73, "volume": 3029364 },
{ "date": new Date('2026-05-25T00:00:00.000Z'), "open": 167.73, "high": 171.03, "low": 166.9, "close": 169.8, "volume": 2426138 },
{ "date": new Date('2026-05-26T00:00:00.000Z'), "open": 169.8, "high": 170.23, "low": 168.44, "close": 169.91, "volume": 1479940 },
{ "date": new Date('2026-05-27T00:00:00.000Z'), "open": 169.91, "high": 171.32, "low": 166.65, "close": 167.8, "volume": 2339555 },
{ "date": new Date('2026-05-28T00:00:00.000Z'), "open": 167.8, "high": 169.88, "low": 165.53, "close": 168.8, "volume": 3143896 },
{ "date": new Date('2026-05-29T00:00:00.000Z'), "open": 168.8, "high": 172.53, "low": 167, "close": 171.42, "volume": 3569036 },
{ "date": new Date('2026-05-30T00:00:00.000Z'), "open": 171.42, "high": 172.42, "low": 171.38, "close": 171.52, "volume": 2395288 },
{ "date": new Date('2026-05-31T00:00:00.000Z'), "open": 171.52, "high": 174.19, "low": 170.56, "close": 171.94, "volume": 1990912 },
{ "date": new Date('2026-06-01T00:00:00.000Z'), "open": 171.94, "high": 173.36, "low": 171.9, "close": 172.14, "volume": 2707900 },
{ "date": new Date('2026-06-02T00:00:00.000Z'), "open": 172.14, "high": 174.94, "low": 171.29, "close": 174.9, "volume": 2731770 },
{ "date": new Date('2026-06-03T00:00:00.000Z'), "open": 174.9, "high": 178.13, "low": 172.81, "close": 176.92, "volume": 3194193 },
{ "date": new Date('2026-06-04T00:00:00.000Z'), "open": 176.92, "high": 178.26, "low": 173.44, "close": 174.62, "volume": 2227849 },
{ "date": new Date('2026-06-05T00:00:00.000Z'), "open": 174.62, "high": 174.99, "low": 171.99, "close": 172.53, "volume": 1952142 },
{ "date": new Date('2026-06-06T00:00:00.000Z'), "open": 172.53, "high": 172.9, "low": 169.67, "close": 172.05, "volume": 1483655 },
{ "date": new Date('2026-06-07T00:00:00.000Z'), "open": 172.05, "high": 173.81, "low": 170.31, "close": 170.99, "volume": 2016829 },
{ "date": new Date('2026-06-08T00:00:00.000Z'), "open": 170.99, "high": 174.14, "low": 169.52, "close": 173.4, "volume": 2847738 },
{ "date": new Date('2026-06-09T00:00:00.000Z'), "open": 173.4, "high": 174.82, "low": 171.09, "close": 172.73, "volume": 3025302 },
{ "date": new Date('2026-06-10T00:00:00.000Z'), "open": 172.73, "high": 175.24, "low": 169.06, "close": 171.38, "volume": 2619529 },
{ "date": new Date('2026-06-11T00:00:00.000Z'), "open": 171.38, "high": 173.96, "low": 168.95, "close": 168.98, "volume": 1944874 },
{ "date": new Date('2026-06-12T00:00:00.000Z'), "open": 168.98, "high": 171.8, "low": 168.17, "close": 171.24, "volume": 3509680 },
{ "date": new Date('2026-06-13T00:00:00.000Z'), "open": 171.24, "high": 174.44, "low": 170.79, "close": 172.07, "volume": 3186503 },
{ "date": new Date('2026-06-14T00:00:00.000Z'), "open": 172.07, "high": 173.69, "low": 167.88, "close": 170.2, "volume": 2170077 },
{ "date": new Date('2026-06-15T00:00:00.000Z'), "open": 170.2, "high": 175.03, "low": 169.27, "close": 172.5, "volume": 2721369 },
{ "date": new Date('2026-06-16T00:00:00.000Z'), "open": 172.5, "high": 176.4, "low": 171.91, "close": 174.49, "volume": 3009601 },
{ "date": new Date('2026-06-17T00:00:00.000Z'), "open": 174.49, "high": 176.68, "low": 173.6, "close": 174.02, "volume": 2714240 },
{ "date": new Date('2026-06-18T00:00:00.000Z'), "open": 174.02, "high": 178.82, "low": 172.25, "close": 176.38, "volume": 2488549 },
{ "date": new Date('2026-06-19T00:00:00.000Z'), "open": 176.38, "high": 179.52, "low": 173.8, "close": 178.3, "volume": 2184126 },
{ "date": new Date('2026-06-20T00:00:00.000Z'), "open": 178.3, "high": 179.44, "low": 177.72, "close": 178.06, "volume": 2206916 },
{ "date": new Date('2026-06-21T00:00:00.000Z'), "open": 178.06, "high": 179.65, "low": 175.56, "close": 176.36, "volume": 2968498 },
{ "date": new Date('2026-06-22T00:00:00.000Z'), "open": 176.36, "high": 178.75, "low": 173.65, "close": 173.66, "volume": 2018748 },
{ "date": new Date('2026-06-23T00:00:00.000Z'), "open": 173.66, "high": 175.77, "low": 173.28, "close": 173.29, "volume": 1493203 },
{ "date": new Date('2026-06-24T00:00:00.000Z'), "open": 173.29, "high": 174.25, "low": 171.2, "close": 174.17, "volume": 1677755 },
{ "date": new Date('2026-06-25T00:00:00.000Z'), "open": 174.17, "high": 176.49, "low": 172.14, "close": 174.18, "volume": 2195255 },
{ "date": new Date('2026-06-26T00:00:00.000Z'), "open": 174.18, "high": 176.23, "low": 170.05, "close": 172.55, "volume": 1956910 },
{ "date": new Date('2026-06-27T00:00:00.000Z'), "open": 172.55, "high": 177.03, "low": 172.1, "close": 175.33, "volume": 2294555 },
{ "date": new Date('2026-06-28T00:00:00.000Z'), "open": 175.33, "high": 180.25, "low": 174.18, "close": 178.33, "volume": 3702584 },
{ "date": new Date('2026-06-29T00:00:00.000Z'), "open": 178.33, "high": 178.83, "low": 175.83, "close": 176.69, "volume": 2561676 },
{ "date": new Date('2026-06-30T00:00:00.000Z'), "open": 176.69, "high": 178.45, "low": 175.77, "close": 176.71, "volume": 1691710 },
{ "date": new Date('2026-07-01T00:00:00.000Z'), "open": 176.71, "high": 177.68, "low": 174.58, "close": 175.69, "volume": 1891064 },
{ "date": new Date('2026-07-02T00:00:00.000Z'), "open": 175.69, "high": 176.87, "low": 172.86, "close": 175.31, "volume": 1862025 },
{ "date": new Date('2026-07-03T00:00:00.000Z'), "open": 175.31, "high": 178.66, "low": 173.7, "close": 178.41, "volume": 2873801 },
{ "date": new Date('2026-07-04T00:00:00.000Z'), "open": 178.41, "high": 181.32, "low": 176.93, "close": 179.67, "volume": 2917261 },
{ "date": new Date('2026-07-05T00:00:00.000Z'), "open": 179.67, "high": 182.32, "low": 176.74, "close": 178.41, "volume": 1924836 },
{ "date": new Date('2026-07-06T00:00:00.000Z'), "open": 178.41, "high": 182.22, "low": 175.89, "close": 181.04, "volume": 2601632 },
{ "date": new Date('2026-07-07T00:00:00.000Z'), "open": 181.04, "high": 181.73, "low": 177.68, "close": 178.74, "volume": 2747583 },
{ "date": new Date('2026-07-08T00:00:00.000Z'), "open": 178.74, "high": 180.38, "low": 176.15, "close": 180.24, "volume": 1829364 },
{ "date": new Date('2026-07-09T00:00:00.000Z'), "open": 180.24, "high": 181.75, "low": 176.53, "close": 178.88, "volume": 2875169 },
{ "date": new Date('2026-07-10T00:00:00.000Z'), "open": 178.88, "high": 180.17, "low": 178.39, "close": 180.16, "volume": 1771891 },
{ "date": new Date('2026-07-11T00:00:00.000Z'), "open": 180.16, "high": 182.25, "low": 178.11, "close": 178.34, "volume": 1760700 },
{ "date": new Date('2026-07-12T00:00:00.000Z'), "open": 178.34, "high": 183.67, "low": 175.68, "close": 181.53, "volume": 2986133 },
{ "date": new Date('2026-07-13T00:00:00.000Z'), "open": 181.53, "high": 183.06, "low": 178.25, "close": 180.7, "volume": 2754332 },
{ "date": new Date('2026-07-14T00:00:00.000Z'), "open": 180.7, "high": 182.04, "low": 178.8, "close": 181.02, "volume": 2853710 },
{ "date": new Date('2026-07-15T00:00:00.000Z'), "open": 181.02, "high": 184.6, "low": 178.5, "close": 182.81, "volume": 3309967 },
{ "date": new Date('2026-07-16T00:00:00.000Z'), "open": 182.81, "high": 187.85, "low": 180.39, "close": 185.86, "volume": 2219317 },
{ "date": new Date('2026-07-17T00:00:00.000Z'), "open": 185.86, "high": 186.1, "low": 181.67, "close": 184.07, "volume": 2014204 },
{ "date": new Date('2026-07-18T00:00:00.000Z'), "open": 184.07, "high": 185.04, "low": 180.87, "close": 182.15, "volume": 2597964 },
{ "date": new Date('2026-07-19T00:00:00.000Z'), "open": 182.15, "high": 185.62, "low": 181.28, "close": 182.95, "volume": 1855149 },
{ "date": new Date('2026-07-20T00:00:00.000Z'), "open": 182.95, "high": 184.31, "low": 179.38, "close": 180.08, "volume": 3538359 },
{ "date": new Date('2026-07-21T00:00:00.000Z'), "open": 180.08, "high": 183.87, "low": 178.35, "close": 182.21, "volume": 2111130 },
{ "date": new Date('2026-07-22T00:00:00.000Z'), "open": 182.21, "high": 183.77, "low": 179.79, "close": 182.59, "volume": 2470964 },
{ "date": new Date('2026-07-23T00:00:00.000Z'), "open": 182.59, "high": 185.11, "low": 178.74, "close": 180, "volume": 2215306 },
{ "date": new Date('2026-07-24T00:00:00.000Z'), "open": 180, "high": 182.37, "low": 179.22, "close": 181.3, "volume": 1930100 },
{ "date": new Date('2026-07-25T00:00:00.000Z'), "open": 181.3, "high": 182.29, "low": 176.78, "close": 179.41, "volume": 2564712 },
{ "date": new Date('2026-07-26T00:00:00.000Z'), "open": 179.41, "high": 181.57, "low": 176.8, "close": 179.78, "volume": 2695389 },
{ "date": new Date('2026-07-27T00:00:00.000Z'), "open": 179.78, "high": 183.37, "low": 177.65, "close": 182.53, "volume": 2612169 },
{ "date": new Date('2026-07-28T00:00:00.000Z'), "open": 182.53, "high": 185.98, "low": 180.64, "close": 185.06, "volume": 2871046 },
{ "date": new Date('2026-07-29T00:00:00.000Z'), "open": 185.06, "high": 185.86, "low": 180.35, "close": 182.69, "volume": 1950375 },
{ "date": new Date('2026-07-30T00:00:00.000Z'), "open": 182.69, "high": 185.15, "low": 177.55, "close": 180.14, "volume": 3537483 },
{ "date": new Date('2026-07-31T00:00:00.000Z'), "open": 180.14, "high": 180.56, "low": 178.7, "close": 179.29, "volume": 3027806 },
{ "date": new Date('2026-08-01T00:00:00.000Z'), "open": 179.29, "high": 183.63, "low": 178.43, "close": 181.63, "volume": 2848629 },
{ "date": new Date('2026-08-02T00:00:00.000Z'), "open": 181.63, "high": 185.46, "low": 179.23, "close": 182.99, "volume": 2719123 },
{ "date": new Date('2026-08-03T00:00:00.000Z'), "open": 182.99, "high": 183.03, "low": 181.76, "close": 181.94, "volume": 2892428 },
{ "date": new Date('2026-08-04T00:00:00.000Z'), "open": 181.94, "high": 184.62, "low": 181.8, "close": 182.87, "volume": 3059787 },
{ "date": new Date('2026-08-05T00:00:00.000Z'), "open": 182.87, "high": 183.86, "low": 179.61, "close": 180.65, "volume": 3153744 },
{ "date": new Date('2026-08-06T00:00:00.000Z'), "open": 180.65, "high": 183.48, "low": 180.36, "close": 183.38, "volume": 2096144 },
{ "date": new Date('2026-08-07T00:00:00.000Z'), "open": 183.38, "high": 183.72, "low": 179.24, "close": 181.35, "volume": 2428129 },
{ "date": new Date('2026-08-08T00:00:00.000Z'), "open": 181.35, "high": 183.15, "low": 178.87, "close": 181.68, "volume": 1957201 },
{ "date": new Date('2026-08-09T00:00:00.000Z'), "open": 181.68, "high": 184.48, "low": 180.15, "close": 184.09, "volume": 3131278 },
{ "date": new Date('2026-08-10T00:00:00.000Z'), "open": 184.09, "high": 187.25, "low": 182.16, "close": 184.76, "volume": 1986018 },
{ "date": new Date('2026-08-11T00:00:00.000Z'), "open": 184.76, "high": 185.27, "low": 181.34, "close": 184.06, "volume": 2629438 },
{ "date": new Date('2026-08-12T00:00:00.000Z'), "open": 184.06, "high": 185.48, "low": 181.89, "close": 182.38, "volume": 2086285 },
{ "date": new Date('2026-08-13T00:00:00.000Z'), "open": 182.38, "high": 185.11, "low": 180.61, "close": 183.66, "volume": 2860446 },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "open": 183.66, "high": 184.63, "low": 180.29, "close": 181.67, "volume": 2398495 },
{ "date": new Date('2026-08-15T00:00:00.000Z'), "open": 181.67, "high": 185.05, "low": 179.28, "close": 184.46, "volume": 2448935 },
{ "date": new Date('2026-08-16T00:00:00.000Z'), "open": 184.46, "high": 187.8, "low": 182.88, "close": 186.13, "volume": 2425201 },
{ "date": new Date('2026-08-17T00:00:00.000Z'), "open": 186.13, "high": 188.94, "low": 184.01, "close": 184.01, "volume": 2897024 },
{ "date": new Date('2026-08-18T00:00:00.000Z'), "open": 184.01, "high": 185.14, "low": 181.96, "close": 185.05, "volume": 2346585 },
{ "date": new Date('2026-08-19T00:00:00.000Z'), "open": 185.05, "high": 187.56, "low": 181.6, "close": 183.2, "volume": 1782162 },
{ "date": new Date('2026-08-20T00:00:00.000Z'), "open": 183.2, "high": 183.37, "low": 181.1, "close": 182.24, "volume": 3222334 },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "open": 182.24, "high": 187.12, "low": 180.33, "close": 184.51, "volume": 2058942 },
{ "date": new Date('2026-08-22T00:00:00.000Z'), "open": 184.51, "high": 187.36, "low": 184.49, "close": 186.44, "volume": 1849602 },
{ "date": new Date('2026-08-23T00:00:00.000Z'), "open": 186.44, "high": 189.61, "low": 183.73, "close": 188.9, "volume": 1968815 },
{ "date": new Date('2026-08-24T00:00:00.000Z'), "open": 188.9, "high": 192.67, "low": 188.31, "close": 191.85, "volume": 3047593 },
{ "date": new Date('2026-08-25T00:00:00.000Z'), "open": 191.85, "high": 194.69, "low": 188.25, "close": 190.53, "volume": 1890866 },
{ "date": new Date('2026-08-26T00:00:00.000Z'), "open": 190.53, "high": 192.03, "low": 188.23, "close": 190.78, "volume": 1826419 },
{ "date": new Date('2026-08-27T00:00:00.000Z'), "open": 190.78, "high": 196.36, "low": 190.07, "close": 193.85, "volume": 2686171 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "open": 193.85, "high": 197.11, "low": 192.05, "close": 194.2, "volume": 2566984 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "open": 194.2, "high": 194.38, "low": 191.92, "close": 192.45, "volume": 2585676 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "open": 192.45, "high": 192.6, "low": 190.83, "close": 191.48, "volume": 2902453 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "open": 191.48, "high": 195.18, "low": 190.07, "close": 194.15, "volume": 2226035 },
{ "date": new Date('2026-09-01T00:00:00.000Z'), "open": 194.15, "high": 194.96, "low": 191.2, "close": 194.68, "volume": 2865378 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "open": 194.68, "high": 195.97, "low": 191.95, "close": 192.18, "volume": 3179562 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "open": 192.18, "high": 197.54, "low": 190.1, "close": 195.29, "volume": 2203328 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "open": 195.29, "high": 200.11, "low": 193.34, "close": 197.72, "volume": 3287887 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "open": 197.72, "high": 202.47, "low": 196.55, "close": 200.86, "volume": 2108982 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "open": 200.86, "high": 202.44, "low": 200.14, "close": 201.7, "volume": 3050788 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "open": 201.7, "high": 206.09, "low": 201.08, "close": 203.76, "volume": 3160303 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "open": 203.76, "high": 205.09, "low": 203.28, "close": 203.62, "volume": 1547552 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "open": 203.62, "high": 206.45, "low": 199.93, "close": 200.54, "volume": 2419421 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "open": 200.54, "high": 203.41, "low": 196.4, "close": 199.31, "volume": 2137922 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "open": 199.31, "high": 201.44, "low": 197.01, "close": 197.94, "volume": 2856143 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "open": 197.94, "high": 200.87, "low": 193.01, "close": 195.54, "volume": 2016849 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "open": 195.54, "high": 197.51, "low": 192.95, "close": 196.79, "volume": 2621817 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "open": 196.79, "high": 199.2, "low": 194.82, "close": 197.52, "volume": 3033046 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "open": 197.52, "high": 203.69, "low": 197, "close": 200.66, "volume": 3041051 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "open": 200.66, "high": 204.11, "low": 198.61, "close": 203.59, "volume": 2082501 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "open": 203.59, "high": 208.28, "low": 201.87, "close": 205.27, "volume": 3222974 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "open": 205.27, "high": 206.64, "low": 203, "close": 203.49, "volume": 2462821 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "open": 203.49, "high": 204.33, "low": 198.71, "close": 200.51, "volume": 2368043 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "open": 200.51, "high": 204.21, "low": 199.53, "close": 204.04, "volume": 2964809 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "open": 204.04, "high": 205.6, "low": 199.82, "close": 201.65, "volume": 3263425 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "open": 201.65, "high": 206.26, "low": 198.81, "close": 203.2, "volume": 3180001 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "open": 203.2, "high": 206.48, "low": 200.12, "close": 205.46, "volume": 2041039 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "open": 205.46, "high": 208.24, "low": 202.34, "close": 203.24, "volume": 2468141 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "open": 203.24, "high": 206, "low": 202.82, "close": 205.56, "volume": 2886985 },
] },
{ "id": "1y", "label": "1Y", "data": [
{ "date": new Date('2025-09-26T00:00:00.000Z'), "open": 168, "high": 169.62, "low": 166.44, "close": 168.25, "volume": 2376004 },
{ "date": new Date('2025-09-27T00:00:00.000Z'), "open": 168.25, "high": 171.85, "low": 168.04, "close": 170.44, "volume": 2774560 },
{ "date": new Date('2025-09-28T00:00:00.000Z'), "open": 170.44, "high": 172.44, "low": 169.19, "close": 171.26, "volume": 2944011 },
{ "date": new Date('2025-09-29T00:00:00.000Z'), "open": 171.26, "high": 173.02, "low": 169.21, "close": 170.99, "volume": 1658505 },
{ "date": new Date('2025-09-30T00:00:00.000Z'), "open": 170.99, "high": 171.71, "low": 168.29, "close": 169.32, "volume": 2375766 },
{ "date": new Date('2025-10-01T00:00:00.000Z'), "open": 169.32, "high": 170.32, "low": 167.77, "close": 169.99, "volume": 2460006 },
{ "date": new Date('2025-10-02T00:00:00.000Z'), "open": 169.99, "high": 172.19, "low": 167.63, "close": 169.72, "volume": 2680722 },
{ "date": new Date('2025-10-03T00:00:00.000Z'), "open": 169.72, "high": 171.34, "low": 168.22, "close": 168.87, "volume": 1631238 },
{ "date": new Date('2025-10-04T00:00:00.000Z'), "open": 168.87, "high": 173, "low": 168.1, "close": 170.45, "volume": 1971537 },
{ "date": new Date('2025-10-05T00:00:00.000Z'), "open": 170.45, "high": 172.98, "low": 169.01, "close": 172.07, "volume": 2698383 },
{ "date": new Date('2025-10-06T00:00:00.000Z'), "open": 172.07, "high": 174.68, "low": 169.83, "close": 174.3, "volume": 3257688 },
{ "date": new Date('2025-10-07T00:00:00.000Z'), "open": 174.3, "high": 174.36, "low": 173.62, "close": 173.82, "volume": 2850391 },
{ "date": new Date('2025-10-08T00:00:00.000Z'), "open": 173.82, "high": 175.42, "low": 173.1, "close": 174.02, "volume": 2211865 },
{ "date": new Date('2025-10-09T00:00:00.000Z'), "open": 174.02, "high": 175.86, "low": 172.3, "close": 175.62, "volume": 1792415 },
{ "date": new Date('2025-10-10T00:00:00.000Z'), "open": 175.62, "high": 177.32, "low": 172.86, "close": 175.5, "volume": 2068163 },
{ "date": new Date('2025-10-11T00:00:00.000Z'), "open": 175.5, "high": 176.46, "low": 175.37, "close": 175.51, "volume": 2555075 },
{ "date": new Date('2025-10-12T00:00:00.000Z'), "open": 175.51, "high": 177.55, "low": 174.44, "close": 175.24, "volume": 2317847 },
{ "date": new Date('2025-10-13T00:00:00.000Z'), "open": 175.24, "high": 177.5, "low": 174.12, "close": 174.55, "volume": 1690321 },
{ "date": new Date('2025-10-14T00:00:00.000Z'), "open": 174.55, "high": 177.21, "low": 174.22, "close": 175.53, "volume": 2183688 },
{ "date": new Date('2025-10-15T00:00:00.000Z'), "open": 175.53, "high": 178.05, "low": 172.73, "close": 175.01, "volume": 2506047 },
{ "date": new Date('2025-10-16T00:00:00.000Z'), "open": 175.01, "high": 177.47, "low": 173.12, "close": 174.69, "volume": 2129860 },
{ "date": new Date('2025-10-17T00:00:00.000Z'), "open": 174.69, "high": 176.07, "low": 173.74, "close": 173.76, "volume": 3030574 },
{ "date": new Date('2025-10-18T00:00:00.000Z'), "open": 173.76, "high": 174.84, "low": 172.47, "close": 172.79, "volume": 1694594 },
{ "date": new Date('2025-10-19T00:00:00.000Z'), "open": 172.79, "high": 175.89, "low": 171.43, "close": 174.43, "volume": 1904016 },
{ "date": new Date('2025-10-20T00:00:00.000Z'), "open": 174.43, "high": 176.65, "low": 172.07, "close": 174.99, "volume": 3072627 },
{ "date": new Date('2025-10-21T00:00:00.000Z'), "open": 174.99, "high": 177.4, "low": 173.45, "close": 175.77, "volume": 2331782 },
{ "date": new Date('2025-10-22T00:00:00.000Z'), "open": 175.77, "high": 177.53, "low": 171.82, "close": 173.55, "volume": 3539201 },
{ "date": new Date('2025-10-23T00:00:00.000Z'), "open": 173.55, "high": 175.34, "low": 173.18, "close": 174.98, "volume": 2764322 },
{ "date": new Date('2025-10-24T00:00:00.000Z'), "open": 174.98, "high": 178.92, "low": 172.51, "close": 177.99, "volume": 2693639 },
{ "date": new Date('2025-10-25T00:00:00.000Z'), "open": 177.99, "high": 181.55, "low": 177.79, "close": 179.76, "volume": 2231591 },
{ "date": new Date('2025-10-26T00:00:00.000Z'), "open": 179.76, "high": 182.32, "low": 178.03, "close": 180.95, "volume": 1985808 },
{ "date": new Date('2025-10-27T00:00:00.000Z'), "open": 180.95, "high": 183.37, "low": 180.7, "close": 182.49, "volume": 2616956 },
{ "date": new Date('2025-10-28T00:00:00.000Z'), "open": 182.49, "high": 182.99, "low": 179.67, "close": 181.94, "volume": 3020438 },
{ "date": new Date('2025-10-29T00:00:00.000Z'), "open": 181.94, "high": 183.69, "low": 180.74, "close": 183.68, "volume": 3161692 },
{ "date": new Date('2025-10-30T00:00:00.000Z'), "open": 183.68, "high": 186.28, "low": 181.91, "close": 184.3, "volume": 1467567 },
{ "date": new Date('2025-10-31T00:00:00.000Z'), "open": 184.3, "high": 185.85, "low": 183.84, "close": 184.46, "volume": 2714578 },
{ "date": new Date('2025-11-01T00:00:00.000Z'), "open": 184.46, "high": 184.7, "low": 179.14, "close": 181.91, "volume": 2946728 },
{ "date": new Date('2025-11-02T00:00:00.000Z'), "open": 181.91, "high": 185.7, "low": 179.36, "close": 183.36, "volume": 3313196 },
{ "date": new Date('2025-11-03T00:00:00.000Z'), "open": 183.36, "high": 183.83, "low": 179.09, "close": 180.74, "volume": 2600538 },
{ "date": new Date('2025-11-04T00:00:00.000Z'), "open": 180.74, "high": 182.21, "low": 180.27, "close": 180.41, "volume": 1501013 },
{ "date": new Date('2025-11-05T00:00:00.000Z'), "open": 180.41, "high": 181.16, "low": 179.21, "close": 180.36, "volume": 2552203 },
{ "date": new Date('2025-11-06T00:00:00.000Z'), "open": 180.36, "high": 181.29, "low": 178.39, "close": 180.01, "volume": 2030022 },
{ "date": new Date('2025-11-07T00:00:00.000Z'), "open": 180.01, "high": 183.92, "low": 178.78, "close": 183.09, "volume": 2472445 },
{ "date": new Date('2025-11-08T00:00:00.000Z'), "open": 183.09, "high": 185.31, "low": 181.52, "close": 184.42, "volume": 2713760 },
{ "date": new Date('2025-11-09T00:00:00.000Z'), "open": 184.42, "high": 184.79, "low": 181.02, "close": 181.48, "volume": 3388796 },
{ "date": new Date('2025-11-10T00:00:00.000Z'), "open": 181.48, "high": 183.75, "low": 178.88, "close": 179.41, "volume": 2874434 },
{ "date": new Date('2025-11-11T00:00:00.000Z'), "open": 179.41, "high": 183.63, "low": 177.18, "close": 181.58, "volume": 2008713 },
{ "date": new Date('2025-11-12T00:00:00.000Z'), "open": 181.58, "high": 183.64, "low": 178.63, "close": 179.22, "volume": 2070968 },
{ "date": new Date('2025-11-13T00:00:00.000Z'), "open": 179.22, "high": 179.48, "low": 176.03, "close": 178.44, "volume": 2581175 },
{ "date": new Date('2025-11-14T00:00:00.000Z'), "open": 178.44, "high": 181.55, "low": 176.37, "close": 179.96, "volume": 2874984 },
{ "date": new Date('2025-11-15T00:00:00.000Z'), "open": 179.96, "high": 182.06, "low": 178.81, "close": 179.43, "volume": 1790012 },
{ "date": new Date('2025-11-16T00:00:00.000Z'), "open": 179.43, "high": 181.15, "low": 177.39, "close": 177.41, "volume": 2753234 },
{ "date": new Date('2025-11-17T00:00:00.000Z'), "open": 177.41, "high": 182.8, "low": 176, "close": 180.41, "volume": 3521242 },
{ "date": new Date('2025-11-18T00:00:00.000Z'), "open": 180.41, "high": 181.86, "low": 175.78, "close": 177.87, "volume": 2351223 },
{ "date": new Date('2025-11-19T00:00:00.000Z'), "open": 177.87, "high": 181.37, "low": 175.49, "close": 180.98, "volume": 2868754 },
{ "date": new Date('2025-11-20T00:00:00.000Z'), "open": 180.98, "high": 186.59, "low": 179.9, "close": 183.8, "volume": 2770997 },
{ "date": new Date('2025-11-21T00:00:00.000Z'), "open": 183.8, "high": 184.08, "low": 183.08, "close": 183.6, "volume": 1526430 },
{ "date": new Date('2025-11-22T00:00:00.000Z'), "open": 183.6, "high": 186.24, "low": 179.71, "close": 181.24, "volume": 2836453 },
{ "date": new Date('2025-11-23T00:00:00.000Z'), "open": 181.24, "high": 183.83, "low": 179.57, "close": 179.79, "volume": 3070500 },
{ "date": new Date('2025-11-24T00:00:00.000Z'), "open": 179.79, "high": 179.96, "low": 177.39, "close": 178.59, "volume": 2247633 },
{ "date": new Date('2025-11-25T00:00:00.000Z'), "open": 178.59, "high": 179.61, "low": 176.26, "close": 176.61, "volume": 3306230 },
{ "date": new Date('2025-11-26T00:00:00.000Z'), "open": 176.61, "high": 178.54, "low": 173.93, "close": 177.29, "volume": 2070876 },
{ "date": new Date('2025-11-27T00:00:00.000Z'), "open": 177.29, "high": 179.39, "low": 176.59, "close": 177.91, "volume": 2318429 },
{ "date": new Date('2025-11-28T00:00:00.000Z'), "open": 177.91, "high": 181.65, "low": 176.62, "close": 180.82, "volume": 2708715 },
{ "date": new Date('2025-11-29T00:00:00.000Z'), "open": 180.82, "high": 181.47, "low": 177.01, "close": 178.74, "volume": 1851015 },
{ "date": new Date('2025-11-30T00:00:00.000Z'), "open": 178.74, "high": 180.77, "low": 176.05, "close": 176.48, "volume": 2225169 },
{ "date": new Date('2025-12-01T00:00:00.000Z'), "open": 176.48, "high": 178.59, "low": 174.66, "close": 176.28, "volume": 2384801 },
{ "date": new Date('2025-12-02T00:00:00.000Z'), "open": 176.28, "high": 178.57, "low": 174.24, "close": 177.55, "volume": 3179221 },
{ "date": new Date('2025-12-03T00:00:00.000Z'), "open": 177.55, "high": 179.48, "low": 176.5, "close": 176.73, "volume": 1738894 },
{ "date": new Date('2025-12-04T00:00:00.000Z'), "open": 176.73, "high": 178.93, "low": 176.46, "close": 177.08, "volume": 2952165 },
{ "date": new Date('2025-12-05T00:00:00.000Z'), "open": 177.08, "high": 180.15, "low": 174.65, "close": 179.78, "volume": 2621607 },
{ "date": new Date('2025-12-06T00:00:00.000Z'), "open": 179.78, "high": 182.87, "low": 177.62, "close": 181.29, "volume": 3306391 },
{ "date": new Date('2025-12-07T00:00:00.000Z'), "open": 181.29, "high": 181.91, "low": 180.28, "close": 181.16, "volume": 2551131 },
{ "date": new Date('2025-12-08T00:00:00.000Z'), "open": 181.16, "high": 182.78, "low": 179.17, "close": 182.64, "volume": 1877325 },
{ "date": new Date('2025-12-09T00:00:00.000Z'), "open": 182.64, "high": 184.75, "low": 181.21, "close": 182.41, "volume": 2968023 },
{ "date": new Date('2025-12-10T00:00:00.000Z'), "open": 182.41, "high": 184.47, "low": 182.15, "close": 184.13, "volume": 2009525 },
{ "date": new Date('2025-12-11T00:00:00.000Z'), "open": 184.13, "high": 186.79, "low": 180.62, "close": 181.32, "volume": 3070357 },
{ "date": new Date('2025-12-12T00:00:00.000Z'), "open": 181.32, "high": 182.22, "low": 178.28, "close": 180.26, "volume": 2842411 },
{ "date": new Date('2025-12-13T00:00:00.000Z'), "open": 180.26, "high": 183.85, "low": 178.73, "close": 181.15, "volume": 2890598 },
{ "date": new Date('2025-12-14T00:00:00.000Z'), "open": 181.15, "high": 182.74, "low": 180.35, "close": 181.65, "volume": 2953104 },
{ "date": new Date('2025-12-15T00:00:00.000Z'), "open": 181.65, "high": 183.17, "low": 178.18, "close": 179.39, "volume": 2986255 },
{ "date": new Date('2025-12-16T00:00:00.000Z'), "open": 179.39, "high": 180.29, "low": 177.55, "close": 179.77, "volume": 1881763 },
{ "date": new Date('2025-12-17T00:00:00.000Z'), "open": 179.77, "high": 180.04, "low": 176.33, "close": 178.75, "volume": 2235638 },
{ "date": new Date('2025-12-18T00:00:00.000Z'), "open": 178.75, "high": 180.31, "low": 175.3, "close": 176.52, "volume": 2197598 },
{ "date": new Date('2025-12-19T00:00:00.000Z'), "open": 176.52, "high": 176.68, "low": 173.05, "close": 174.09, "volume": 3446510 },
{ "date": new Date('2025-12-20T00:00:00.000Z'), "open": 174.09, "high": 176.51, "low": 172.89, "close": 173.8, "volume": 1974833 },
{ "date": new Date('2025-12-21T00:00:00.000Z'), "open": 173.8, "high": 174.65, "low": 172.82, "close": 174.63, "volume": 2455323 },
{ "date": new Date('2025-12-22T00:00:00.000Z'), "open": 174.63, "high": 178.48, "low": 172.96, "close": 176.56, "volume": 3402154 },
{ "date": new Date('2025-12-23T00:00:00.000Z'), "open": 176.56, "high": 177.95, "low": 176.32, "close": 177.5, "volume": 1768634 },
{ "date": new Date('2025-12-24T00:00:00.000Z'), "open": 177.5, "high": 179.81, "low": 175.57, "close": 175.99, "volume": 1909374 },
{ "date": new Date('2025-12-25T00:00:00.000Z'), "open": 175.99, "high": 178.24, "low": 171.59, "close": 173.57, "volume": 1948920 },
{ "date": new Date('2025-12-26T00:00:00.000Z'), "open": 173.57, "high": 173.6, "low": 172.38, "close": 172.98, "volume": 2815526 },
{ "date": new Date('2025-12-27T00:00:00.000Z'), "open": 172.98, "high": 173.01, "low": 172.87, "close": 172.99, "volume": 1373445 },
{ "date": new Date('2025-12-28T00:00:00.000Z'), "open": 172.99, "high": 174.32, "low": 172.41, "close": 172.45, "volume": 2913342 },
{ "date": new Date('2025-12-29T00:00:00.000Z'), "open": 172.45, "high": 175.69, "low": 171.53, "close": 175.04, "volume": 2157600 },
{ "date": new Date('2025-12-30T00:00:00.000Z'), "open": 175.04, "high": 175.12, "low": 172.06, "close": 173.16, "volume": 3055756 },
{ "date": new Date('2025-12-31T00:00:00.000Z'), "open": 173.16, "high": 175.99, "low": 170.89, "close": 174.94, "volume": 2552465 },
{ "date": new Date('2026-01-01T00:00:00.000Z'), "open": 174.94, "high": 176.6, "low": 172.25, "close": 173.98, "volume": 2670145 },
{ "date": new Date('2026-01-02T00:00:00.000Z'), "open": 173.98, "high": 175.86, "low": 172.3, "close": 173.53, "volume": 2114092 },
{ "date": new Date('2026-01-03T00:00:00.000Z'), "open": 173.53, "high": 176.09, "low": 172.42, "close": 173.23, "volume": 2459980 },
{ "date": new Date('2026-01-04T00:00:00.000Z'), "open": 173.23, "high": 174.91, "low": 170.51, "close": 170.84, "volume": 2974654 },
{ "date": new Date('2026-01-05T00:00:00.000Z'), "open": 170.84, "high": 172.95, "low": 167.51, "close": 169.4, "volume": 2015939 },
{ "date": new Date('2026-01-06T00:00:00.000Z'), "open": 169.4, "high": 173.31, "low": 168.47, "close": 172.22, "volume": 2394684 },
{ "date": new Date('2026-01-07T00:00:00.000Z'), "open": 172.22, "high": 174.55, "low": 169.19, "close": 169.54, "volume": 2857399 },
{ "date": new Date('2026-01-08T00:00:00.000Z'), "open": 169.54, "high": 174.08, "low": 169.15, "close": 171.76, "volume": 3409348 },
{ "date": new Date('2026-01-09T00:00:00.000Z'), "open": 171.76, "high": 173.22, "low": 170.42, "close": 171.35, "volume": 2012173 },
{ "date": new Date('2026-01-10T00:00:00.000Z'), "open": 171.35, "high": 171.42, "low": 168.49, "close": 169.17, "volume": 1972764 },
{ "date": new Date('2026-01-11T00:00:00.000Z'), "open": 169.17, "high": 170.75, "low": 166.98, "close": 168.18, "volume": 1988412 },
{ "date": new Date('2026-01-12T00:00:00.000Z'), "open": 168.18, "high": 170.09, "low": 166.22, "close": 168.48, "volume": 2961721 },
{ "date": new Date('2026-01-13T00:00:00.000Z'), "open": 168.48, "high": 169.6, "low": 166.59, "close": 166.89, "volume": 2902902 },
{ "date": new Date('2026-01-14T00:00:00.000Z'), "open": 166.89, "high": 167.29, "low": 164.38, "close": 166.01, "volume": 1985029 },
{ "date": new Date('2026-01-15T00:00:00.000Z'), "open": 166.01, "high": 167.68, "low": 163.79, "close": 164.28, "volume": 2170519 },
{ "date": new Date('2026-01-16T00:00:00.000Z'), "open": 164.28, "high": 164.31, "low": 162.74, "close": 162.97, "volume": 1761474 },
{ "date": new Date('2026-01-17T00:00:00.000Z'), "open": 162.97, "high": 164.26, "low": 161.36, "close": 162.17, "volume": 3161593 },
{ "date": new Date('2026-01-18T00:00:00.000Z'), "open": 162.17, "high": 165.35, "low": 161.46, "close": 163.56, "volume": 2815391 },
{ "date": new Date('2026-01-19T00:00:00.000Z'), "open": 163.56, "high": 165.8, "low": 162.33, "close": 163.3, "volume": 2675676 },
{ "date": new Date('2026-01-20T00:00:00.000Z'), "open": 163.3, "high": 163.91, "low": 159.37, "close": 161.68, "volume": 2235379 },
{ "date": new Date('2026-01-21T00:00:00.000Z'), "open": 161.68, "high": 163.81, "low": 157.37, "close": 159.49, "volume": 2333442 },
{ "date": new Date('2026-01-22T00:00:00.000Z'), "open": 159.49, "high": 159.85, "low": 155.79, "close": 156.97, "volume": 2070253 },
{ "date": new Date('2026-01-23T00:00:00.000Z'), "open": 156.97, "high": 159.8, "low": 155.35, "close": 158.09, "volume": 2511882 },
{ "date": new Date('2026-01-24T00:00:00.000Z'), "open": 158.09, "high": 160.35, "low": 154.41, "close": 156.72, "volume": 2787778 },
{ "date": new Date('2026-01-25T00:00:00.000Z'), "open": 156.72, "high": 157.51, "low": 154.13, "close": 154.87, "volume": 2682325 },
{ "date": new Date('2026-01-26T00:00:00.000Z'), "open": 154.87, "high": 158.95, "low": 154.73, "close": 156.67, "volume": 2287307 },
{ "date": new Date('2026-01-27T00:00:00.000Z'), "open": 156.67, "high": 158.93, "low": 154.86, "close": 156.28, "volume": 2212214 },
{ "date": new Date('2026-01-28T00:00:00.000Z'), "open": 156.28, "high": 157.82, "low": 153.26, "close": 154.6, "volume": 2469048 },
{ "date": new Date('2026-01-29T00:00:00.000Z'), "open": 154.6, "high": 158, "low": 152.35, "close": 156.89, "volume": 2202094 },
{ "date": new Date('2026-01-30T00:00:00.000Z'), "open": 156.89, "high": 158.34, "low": 153.8, "close": 155.69, "volume": 2188116 },
{ "date": new Date('2026-01-31T00:00:00.000Z'), "open": 155.69, "high": 155.82, "low": 153.88, "close": 154.68, "volume": 3000837 },
{ "date": new Date('2026-02-01T00:00:00.000Z'), "open": 154.68, "high": 157.63, "low": 153.65, "close": 156.94, "volume": 2683389 },
{ "date": new Date('2026-02-02T00:00:00.000Z'), "open": 156.94, "high": 157.92, "low": 154.85, "close": 156.59, "volume": 1596920 },
{ "date": new Date('2026-02-03T00:00:00.000Z'), "open": 156.59, "high": 157.14, "low": 153.58, "close": 155.85, "volume": 1792765 },
{ "date": new Date('2026-02-04T00:00:00.000Z'), "open": 155.85, "high": 157.23, "low": 152.91, "close": 153.45, "volume": 1994696 },
{ "date": new Date('2026-02-05T00:00:00.000Z'), "open": 153.45, "high": 156.98, "low": 153.08, "close": 155.33, "volume": 3111199 },
{ "date": new Date('2026-02-06T00:00:00.000Z'), "open": 155.33, "high": 155.5, "low": 152.48, "close": 152.91, "volume": 2063716 },
{ "date": new Date('2026-02-07T00:00:00.000Z'), "open": 152.91, "high": 155.09, "low": 148.54, "close": 150.54, "volume": 3294200 },
{ "date": new Date('2026-02-08T00:00:00.000Z'), "open": 150.54, "high": 152.85, "low": 148.76, "close": 151.46, "volume": 2024517 },
{ "date": new Date('2026-02-09T00:00:00.000Z'), "open": 151.46, "high": 152.36, "low": 149.06, "close": 149.32, "volume": 2395854 },
{ "date": new Date('2026-02-10T00:00:00.000Z'), "open": 149.32, "high": 149.97, "low": 148.73, "close": 149.03, "volume": 2859938 },
{ "date": new Date('2026-02-11T00:00:00.000Z'), "open": 149.03, "high": 151.09, "low": 147.39, "close": 149.09, "volume": 1576157 },
{ "date": new Date('2026-02-12T00:00:00.000Z'), "open": 149.09, "high": 150.87, "low": 149.05, "close": 149.35, "volume": 2056184 },
{ "date": new Date('2026-02-13T00:00:00.000Z'), "open": 149.35, "high": 152.44, "low": 148.48, "close": 150.54, "volume": 2730759 },
{ "date": new Date('2026-02-14T00:00:00.000Z'), "open": 150.54, "high": 151.03, "low": 149.1, "close": 150.42, "volume": 2996948 },
{ "date": new Date('2026-02-15T00:00:00.000Z'), "open": 150.42, "high": 150.6, "low": 148.32, "close": 149.07, "volume": 2528822 },
{ "date": new Date('2026-02-16T00:00:00.000Z'), "open": 149.07, "high": 150.8, "low": 146.04, "close": 148.24, "volume": 2264302 },
{ "date": new Date('2026-02-17T00:00:00.000Z'), "open": 148.24, "high": 148.52, "low": 146.16, "close": 147.73, "volume": 2201103 },
{ "date": new Date('2026-02-18T00:00:00.000Z'), "open": 147.73, "high": 148.01, "low": 146.59, "close": 146.64, "volume": 2586394 },
{ "date": new Date('2026-02-19T00:00:00.000Z'), "open": 146.64, "high": 147.99, "low": 144.47, "close": 145.29, "volume": 3155410 },
{ "date": new Date('2026-02-20T00:00:00.000Z'), "open": 145.29, "high": 147.38, "low": 144.5, "close": 147.14, "volume": 2544257 },
{ "date": new Date('2026-02-21T00:00:00.000Z'), "open": 147.14, "high": 147.48, "low": 144.35, "close": 146.17, "volume": 1961931 },
{ "date": new Date('2026-02-22T00:00:00.000Z'), "open": 146.17, "high": 146.85, "low": 145.02, "close": 146.65, "volume": 2479013 },
{ "date": new Date('2026-02-23T00:00:00.000Z'), "open": 146.65, "high": 149.05, "low": 145.57, "close": 147.95, "volume": 3281713 },
{ "date": new Date('2026-02-24T00:00:00.000Z'), "open": 147.95, "high": 149.61, "low": 145.35, "close": 146.29, "volume": 3066156 },
{ "date": new Date('2026-02-25T00:00:00.000Z'), "open": 146.29, "high": 148.62, "low": 145.15, "close": 146.95, "volume": 2677601 },
{ "date": new Date('2026-02-26T00:00:00.000Z'), "open": 146.95, "high": 147.62, "low": 143.72, "close": 144.66, "volume": 3110522 },
{ "date": new Date('2026-02-27T00:00:00.000Z'), "open": 144.66, "high": 146.12, "low": 142.95, "close": 144.23, "volume": 2550500 },
{ "date": new Date('2026-02-28T00:00:00.000Z'), "open": 144.23, "high": 145.97, "low": 142.59, "close": 145.96, "volume": 3144137 },
{ "date": new Date('2026-03-01T00:00:00.000Z'), "open": 145.96, "high": 147.66, "low": 145.54, "close": 146.36, "volume": 1701330 },
{ "date": new Date('2026-03-02T00:00:00.000Z'), "open": 146.36, "high": 147.07, "low": 145.37, "close": 146.7, "volume": 2106014 },
{ "date": new Date('2026-03-03T00:00:00.000Z'), "open": 146.7, "high": 146.92, "low": 144.64, "close": 145.36, "volume": 3008395 },
{ "date": new Date('2026-03-04T00:00:00.000Z'), "open": 145.36, "high": 148.16, "low": 145.1, "close": 146.29, "volume": 1866897 },
{ "date": new Date('2026-03-05T00:00:00.000Z'), "open": 146.29, "high": 147.59, "low": 142.01, "close": 144.11, "volume": 3118656 },
{ "date": new Date('2026-03-06T00:00:00.000Z'), "open": 144.11, "high": 144.82, "low": 141.68, "close": 142.71, "volume": 1886003 },
{ "date": new Date('2026-03-07T00:00:00.000Z'), "open": 142.71, "high": 144.75, "low": 141.62, "close": 142.75, "volume": 2058656 },
{ "date": new Date('2026-03-08T00:00:00.000Z'), "open": 142.75, "high": 144.17, "low": 139.85, "close": 140.87, "volume": 3564841 },
{ "date": new Date('2026-03-09T00:00:00.000Z'), "open": 140.87, "high": 141.22, "low": 138.3, "close": 140.29, "volume": 2404470 },
{ "date": new Date('2026-03-10T00:00:00.000Z'), "open": 140.29, "high": 140.72, "low": 138.49, "close": 139.15, "volume": 2596164 },
{ "date": new Date('2026-03-11T00:00:00.000Z'), "open": 139.15, "high": 142.69, "low": 138.73, "close": 140.58, "volume": 2744217 },
{ "date": new Date('2026-03-12T00:00:00.000Z'), "open": 140.58, "high": 143.13, "low": 138.53, "close": 141.85, "volume": 2583628 },
{ "date": new Date('2026-03-13T00:00:00.000Z'), "open": 141.85, "high": 144.46, "low": 141.71, "close": 143.7, "volume": 3505747 },
{ "date": new Date('2026-03-14T00:00:00.000Z'), "open": 143.7, "high": 144.75, "low": 143.49, "close": 144.51, "volume": 1798013 },
{ "date": new Date('2026-03-15T00:00:00.000Z'), "open": 144.51, "high": 146.02, "low": 142.27, "close": 143.76, "volume": 2189504 },
{ "date": new Date('2026-03-16T00:00:00.000Z'), "open": 143.76, "high": 145.63, "low": 142.25, "close": 144.22, "volume": 2133603 },
{ "date": new Date('2026-03-17T00:00:00.000Z'), "open": 144.22, "high": 145.99, "low": 142.01, "close": 142.34, "volume": 2820359 },
{ "date": new Date('2026-03-18T00:00:00.000Z'), "open": 142.34, "high": 146.51, "low": 140.17, "close": 144.6, "volume": 2747946 },
{ "date": new Date('2026-03-19T00:00:00.000Z'), "open": 144.6, "high": 146.67, "low": 142.36, "close": 144, "volume": 2751792 },
{ "date": new Date('2026-03-20T00:00:00.000Z'), "open": 144, "high": 146.39, "low": 143.41, "close": 146, "volume": 3043261 },
{ "date": new Date('2026-03-21T00:00:00.000Z'), "open": 146, "high": 147.03, "low": 143.55, "close": 145.05, "volume": 2520335 },
{ "date": new Date('2026-03-22T00:00:00.000Z'), "open": 145.05, "high": 147.68, "low": 145.04, "close": 147.23, "volume": 3087607 },
{ "date": new Date('2026-03-23T00:00:00.000Z'), "open": 147.23, "high": 149.76, "low": 145.08, "close": 148.29, "volume": 1950152 },
{ "date": new Date('2026-03-24T00:00:00.000Z'), "open": 148.29, "high": 150.56, "low": 145.23, "close": 146.67, "volume": 2224052 },
{ "date": new Date('2026-03-25T00:00:00.000Z'), "open": 146.67, "high": 148.3, "low": 144.29, "close": 145.82, "volume": 3168676 },
{ "date": new Date('2026-03-26T00:00:00.000Z'), "open": 145.82, "high": 146.53, "low": 144.94, "close": 145.14, "volume": 1600881 },
{ "date": new Date('2026-03-27T00:00:00.000Z'), "open": 145.14, "high": 146.06, "low": 143.4, "close": 145.73, "volume": 2635213 },
{ "date": new Date('2026-03-28T00:00:00.000Z'), "open": 145.73, "high": 148.07, "low": 145.41, "close": 147.17, "volume": 2899898 },
{ "date": new Date('2026-03-29T00:00:00.000Z'), "open": 147.17, "high": 151.54, "low": 146.53, "close": 149.83, "volume": 2585536 },
{ "date": new Date('2026-03-30T00:00:00.000Z'), "open": 149.83, "high": 150.65, "low": 146.57, "close": 148.2, "volume": 1801152 },
{ "date": new Date('2026-03-31T00:00:00.000Z'), "open": 148.2, "high": 148.77, "low": 146.89, "close": 148.5, "volume": 2870322 },
{ "date": new Date('2026-04-01T00:00:00.000Z'), "open": 148.5, "high": 153.27, "low": 147.82, "close": 151.01, "volume": 3444678 },
{ "date": new Date('2026-04-02T00:00:00.000Z'), "open": 151.01, "high": 152.29, "low": 148.98, "close": 151.21, "volume": 1561281 },
{ "date": new Date('2026-04-03T00:00:00.000Z'), "open": 151.21, "high": 154.03, "low": 149.25, "close": 152.63, "volume": 2220081 },
{ "date": new Date('2026-04-04T00:00:00.000Z'), "open": 152.63, "high": 152.79, "low": 149.52, "close": 151.13, "volume": 2781695 },
{ "date": new Date('2026-04-05T00:00:00.000Z'), "open": 151.13, "high": 154.6, "low": 150.87, "close": 153.81, "volume": 2867194 },
{ "date": new Date('2026-04-06T00:00:00.000Z'), "open": 153.81, "high": 157.44, "low": 152.33, "close": 156.09, "volume": 3444996 },
{ "date": new Date('2026-04-07T00:00:00.000Z'), "open": 156.09, "high": 156.68, "low": 154.82, "close": 156.57, "volume": 1744423 },
{ "date": new Date('2026-04-08T00:00:00.000Z'), "open": 156.57, "high": 157.78, "low": 153.72, "close": 155.24, "volume": 2450699 },
{ "date": new Date('2026-04-09T00:00:00.000Z'), "open": 155.24, "high": 155.25, "low": 152.91, "close": 153.65, "volume": 1987237 },
{ "date": new Date('2026-04-10T00:00:00.000Z'), "open": 153.65, "high": 156.22, "low": 152.27, "close": 154.39, "volume": 1666324 },
{ "date": new Date('2026-04-11T00:00:00.000Z'), "open": 154.39, "high": 155.51, "low": 153.82, "close": 155.36, "volume": 2021039 },
{ "date": new Date('2026-04-12T00:00:00.000Z'), "open": 155.36, "high": 155.75, "low": 155.11, "close": 155.29, "volume": 2937036 },
{ "date": new Date('2026-04-13T00:00:00.000Z'), "open": 155.29, "high": 155.56, "low": 151.57, "close": 153.7, "volume": 1996865 },
{ "date": new Date('2026-04-14T00:00:00.000Z'), "open": 153.7, "high": 156.04, "low": 151.32, "close": 151.8, "volume": 2238815 },
{ "date": new Date('2026-04-15T00:00:00.000Z'), "open": 151.8, "high": 155.39, "low": 150.25, "close": 153.74, "volume": 3217911 },
{ "date": new Date('2026-04-16T00:00:00.000Z'), "open": 153.74, "high": 157.57, "low": 151.84, "close": 155.24, "volume": 2119930 },
{ "date": new Date('2026-04-17T00:00:00.000Z'), "open": 155.24, "high": 156.06, "low": 152.91, "close": 154.93, "volume": 1760989 },
{ "date": new Date('2026-04-18T00:00:00.000Z'), "open": 154.93, "high": 156.61, "low": 151.45, "close": 152.56, "volume": 2411306 },
{ "date": new Date('2026-04-19T00:00:00.000Z'), "open": 152.56, "high": 153.69, "low": 148.84, "close": 150.35, "volume": 2106919 },
{ "date": new Date('2026-04-20T00:00:00.000Z'), "open": 150.35, "high": 153.5, "low": 150.2, "close": 152.49, "volume": 2449872 },
{ "date": new Date('2026-04-21T00:00:00.000Z'), "open": 152.49, "high": 154.63, "low": 150.52, "close": 150.85, "volume": 2773442 },
{ "date": new Date('2026-04-22T00:00:00.000Z'), "open": 150.85, "high": 152.73, "low": 148.78, "close": 150.74, "volume": 1461180 },
{ "date": new Date('2026-04-23T00:00:00.000Z'), "open": 150.74, "high": 153.37, "low": 149.77, "close": 153.34, "volume": 3687707 },
{ "date": new Date('2026-04-24T00:00:00.000Z'), "open": 153.34, "high": 153.34, "low": 150.12, "close": 152.09, "volume": 2527334 },
{ "date": new Date('2026-04-25T00:00:00.000Z'), "open": 152.09, "high": 153.71, "low": 150.52, "close": 152.37, "volume": 1983212 },
{ "date": new Date('2026-04-26T00:00:00.000Z'), "open": 152.37, "high": 154.61, "low": 150.07, "close": 152.73, "volume": 2228479 },
{ "date": new Date('2026-04-27T00:00:00.000Z'), "open": 152.73, "high": 156.76, "low": 152.42, "close": 154.44, "volume": 2173658 },
{ "date": new Date('2026-04-28T00:00:00.000Z'), "open": 154.44, "high": 155.74, "low": 152.48, "close": 155.66, "volume": 2669832 },
{ "date": new Date('2026-04-29T00:00:00.000Z'), "open": 155.66, "high": 158.19, "low": 154.64, "close": 156.77, "volume": 3039806 },
{ "date": new Date('2026-04-30T00:00:00.000Z'), "open": 156.77, "high": 160.39, "low": 154.5, "close": 159.22, "volume": 2032129 },
{ "date": new Date('2026-05-01T00:00:00.000Z'), "open": 159.22, "high": 159.61, "low": 156.08, "close": 157.01, "volume": 3142221 },
{ "date": new Date('2026-05-02T00:00:00.000Z'), "open": 157.01, "high": 157.59, "low": 154.3, "close": 155.92, "volume": 2751851 },
{ "date": new Date('2026-05-03T00:00:00.000Z'), "open": 155.92, "high": 159.53, "low": 153.9, "close": 158.46, "volume": 2063295 },
{ "date": new Date('2026-05-04T00:00:00.000Z'), "open": 158.46, "high": 161.28, "low": 157.89, "close": 160.86, "volume": 3193688 },
{ "date": new Date('2026-05-05T00:00:00.000Z'), "open": 160.86, "high": 163.29, "low": 158.21, "close": 160.34, "volume": 2776757 },
{ "date": new Date('2026-05-06T00:00:00.000Z'), "open": 160.34, "high": 162.91, "low": 158.24, "close": 160.84, "volume": 1530875 },
{ "date": new Date('2026-05-07T00:00:00.000Z'), "open": 160.84, "high": 165.76, "low": 159.81, "close": 163.66, "volume": 3272444 },
{ "date": new Date('2026-05-08T00:00:00.000Z'), "open": 163.66, "high": 167.1, "low": 162.88, "close": 165, "volume": 2914948 },
{ "date": new Date('2026-05-09T00:00:00.000Z'), "open": 165, "high": 166.61, "low": 163.64, "close": 164.19, "volume": 2912552 },
{ "date": new Date('2026-05-10T00:00:00.000Z'), "open": 164.19, "high": 166.67, "low": 162.65, "close": 162.88, "volume": 1857223 },
{ "date": new Date('2026-05-11T00:00:00.000Z'), "open": 162.88, "high": 163.4, "low": 161.22, "close": 163.06, "volume": 2688559 },
{ "date": new Date('2026-05-12T00:00:00.000Z'), "open": 163.06, "high": 167.26, "low": 161.86, "close": 164.94, "volume": 3262744 },
{ "date": new Date('2026-05-13T00:00:00.000Z'), "open": 164.94, "high": 169.28, "low": 163.15, "close": 167.47, "volume": 2715268 },
{ "date": new Date('2026-05-14T00:00:00.000Z'), "open": 167.47, "high": 169.14, "low": 166.23, "close": 167.62, "volume": 2496159 },
{ "date": new Date('2026-05-15T00:00:00.000Z'), "open": 167.62, "high": 169.78, "low": 166.89, "close": 169.28, "volume": 2835271 },
{ "date": new Date('2026-05-16T00:00:00.000Z'), "open": 169.28, "high": 170.41, "low": 166.83, "close": 168.98, "volume": 1851239 },
{ "date": new Date('2026-05-17T00:00:00.000Z'), "open": 168.98, "high": 172.53, "low": 167.83, "close": 170.99, "volume": 2175470 },
{ "date": new Date('2026-05-18T00:00:00.000Z'), "open": 170.99, "high": 173.45, "low": 168.74, "close": 169.09, "volume": 2317336 },
{ "date": new Date('2026-05-19T00:00:00.000Z'), "open": 169.09, "high": 172.51, "low": 166.85, "close": 170.96, "volume": 2279714 },
{ "date": new Date('2026-05-20T00:00:00.000Z'), "open": 170.96, "high": 173.64, "low": 169.41, "close": 171.33, "volume": 2598995 },
{ "date": new Date('2026-05-21T00:00:00.000Z'), "open": 171.33, "high": 173.01, "low": 169.05, "close": 170, "volume": 1941274 },
{ "date": new Date('2026-05-22T00:00:00.000Z'), "open": 170, "high": 170.87, "low": 167.4, "close": 170.01, "volume": 2223511 },
{ "date": new Date('2026-05-23T00:00:00.000Z'), "open": 170.01, "high": 170.91, "low": 166.5, "close": 168.73, "volume": 2776761 },
{ "date": new Date('2026-05-24T00:00:00.000Z'), "open": 168.73, "high": 169.99, "low": 166.96, "close": 167.73, "volume": 3029364 },
{ "date": new Date('2026-05-25T00:00:00.000Z'), "open": 167.73, "high": 171.03, "low": 166.9, "close": 169.8, "volume": 2426138 },
{ "date": new Date('2026-05-26T00:00:00.000Z'), "open": 169.8, "high": 170.23, "low": 168.44, "close": 169.91, "volume": 1479940 },
{ "date": new Date('2026-05-27T00:00:00.000Z'), "open": 169.91, "high": 171.32, "low": 166.65, "close": 167.8, "volume": 2339555 },
{ "date": new Date('2026-05-28T00:00:00.000Z'), "open": 167.8, "high": 169.88, "low": 165.53, "close": 168.8, "volume": 3143896 },
{ "date": new Date('2026-05-29T00:00:00.000Z'), "open": 168.8, "high": 172.53, "low": 167, "close": 171.42, "volume": 3569036 },
{ "date": new Date('2026-05-30T00:00:00.000Z'), "open": 171.42, "high": 172.42, "low": 171.38, "close": 171.52, "volume": 2395288 },
{ "date": new Date('2026-05-31T00:00:00.000Z'), "open": 171.52, "high": 174.19, "low": 170.56, "close": 171.94, "volume": 1990912 },
{ "date": new Date('2026-06-01T00:00:00.000Z'), "open": 171.94, "high": 173.36, "low": 171.9, "close": 172.14, "volume": 2707900 },
{ "date": new Date('2026-06-02T00:00:00.000Z'), "open": 172.14, "high": 174.94, "low": 171.29, "close": 174.9, "volume": 2731770 },
{ "date": new Date('2026-06-03T00:00:00.000Z'), "open": 174.9, "high": 178.13, "low": 172.81, "close": 176.92, "volume": 3194193 },
{ "date": new Date('2026-06-04T00:00:00.000Z'), "open": 176.92, "high": 178.26, "low": 173.44, "close": 174.62, "volume": 2227849 },
{ "date": new Date('2026-06-05T00:00:00.000Z'), "open": 174.62, "high": 174.99, "low": 171.99, "close": 172.53, "volume": 1952142 },
{ "date": new Date('2026-06-06T00:00:00.000Z'), "open": 172.53, "high": 172.9, "low": 169.67, "close": 172.05, "volume": 1483655 },
{ "date": new Date('2026-06-07T00:00:00.000Z'), "open": 172.05, "high": 173.81, "low": 170.31, "close": 170.99, "volume": 2016829 },
{ "date": new Date('2026-06-08T00:00:00.000Z'), "open": 170.99, "high": 174.14, "low": 169.52, "close": 173.4, "volume": 2847738 },
{ "date": new Date('2026-06-09T00:00:00.000Z'), "open": 173.4, "high": 174.82, "low": 171.09, "close": 172.73, "volume": 3025302 },
{ "date": new Date('2026-06-10T00:00:00.000Z'), "open": 172.73, "high": 175.24, "low": 169.06, "close": 171.38, "volume": 2619529 },
{ "date": new Date('2026-06-11T00:00:00.000Z'), "open": 171.38, "high": 173.96, "low": 168.95, "close": 168.98, "volume": 1944874 },
{ "date": new Date('2026-06-12T00:00:00.000Z'), "open": 168.98, "high": 171.8, "low": 168.17, "close": 171.24, "volume": 3509680 },
{ "date": new Date('2026-06-13T00:00:00.000Z'), "open": 171.24, "high": 174.44, "low": 170.79, "close": 172.07, "volume": 3186503 },
{ "date": new Date('2026-06-14T00:00:00.000Z'), "open": 172.07, "high": 173.69, "low": 167.88, "close": 170.2, "volume": 2170077 },
{ "date": new Date('2026-06-15T00:00:00.000Z'), "open": 170.2, "high": 175.03, "low": 169.27, "close": 172.5, "volume": 2721369 },
{ "date": new Date('2026-06-16T00:00:00.000Z'), "open": 172.5, "high": 176.4, "low": 171.91, "close": 174.49, "volume": 3009601 },
{ "date": new Date('2026-06-17T00:00:00.000Z'), "open": 174.49, "high": 176.68, "low": 173.6, "close": 174.02, "volume": 2714240 },
{ "date": new Date('2026-06-18T00:00:00.000Z'), "open": 174.02, "high": 178.82, "low": 172.25, "close": 176.38, "volume": 2488549 },
{ "date": new Date('2026-06-19T00:00:00.000Z'), "open": 176.38, "high": 179.52, "low": 173.8, "close": 178.3, "volume": 2184126 },
{ "date": new Date('2026-06-20T00:00:00.000Z'), "open": 178.3, "high": 179.44, "low": 177.72, "close": 178.06, "volume": 2206916 },
{ "date": new Date('2026-06-21T00:00:00.000Z'), "open": 178.06, "high": 179.65, "low": 175.56, "close": 176.36, "volume": 2968498 },
{ "date": new Date('2026-06-22T00:00:00.000Z'), "open": 176.36, "high": 178.75, "low": 173.65, "close": 173.66, "volume": 2018748 },
{ "date": new Date('2026-06-23T00:00:00.000Z'), "open": 173.66, "high": 175.77, "low": 173.28, "close": 173.29, "volume": 1493203 },
{ "date": new Date('2026-06-24T00:00:00.000Z'), "open": 173.29, "high": 174.25, "low": 171.2, "close": 174.17, "volume": 1677755 },
{ "date": new Date('2026-06-25T00:00:00.000Z'), "open": 174.17, "high": 176.49, "low": 172.14, "close": 174.18, "volume": 2195255 },
{ "date": new Date('2026-06-26T00:00:00.000Z'), "open": 174.18, "high": 176.23, "low": 170.05, "close": 172.55, "volume": 1956910 },
{ "date": new Date('2026-06-27T00:00:00.000Z'), "open": 172.55, "high": 177.03, "low": 172.1, "close": 175.33, "volume": 2294555 },
{ "date": new Date('2026-06-28T00:00:00.000Z'), "open": 175.33, "high": 180.25, "low": 174.18, "close": 178.33, "volume": 3702584 },
{ "date": new Date('2026-06-29T00:00:00.000Z'), "open": 178.33, "high": 178.83, "low": 175.83, "close": 176.69, "volume": 2561676 },
{ "date": new Date('2026-06-30T00:00:00.000Z'), "open": 176.69, "high": 178.45, "low": 175.77, "close": 176.71, "volume": 1691710 },
{ "date": new Date('2026-07-01T00:00:00.000Z'), "open": 176.71, "high": 177.68, "low": 174.58, "close": 175.69, "volume": 1891064 },
{ "date": new Date('2026-07-02T00:00:00.000Z'), "open": 175.69, "high": 176.87, "low": 172.86, "close": 175.31, "volume": 1862025 },
{ "date": new Date('2026-07-03T00:00:00.000Z'), "open": 175.31, "high": 178.66, "low": 173.7, "close": 178.41, "volume": 2873801 },
{ "date": new Date('2026-07-04T00:00:00.000Z'), "open": 178.41, "high": 181.32, "low": 176.93, "close": 179.67, "volume": 2917261 },
{ "date": new Date('2026-07-05T00:00:00.000Z'), "open": 179.67, "high": 182.32, "low": 176.74, "close": 178.41, "volume": 1924836 },
{ "date": new Date('2026-07-06T00:00:00.000Z'), "open": 178.41, "high": 182.22, "low": 175.89, "close": 181.04, "volume": 2601632 },
{ "date": new Date('2026-07-07T00:00:00.000Z'), "open": 181.04, "high": 181.73, "low": 177.68, "close": 178.74, "volume": 2747583 },
{ "date": new Date('2026-07-08T00:00:00.000Z'), "open": 178.74, "high": 180.38, "low": 176.15, "close": 180.24, "volume": 1829364 },
{ "date": new Date('2026-07-09T00:00:00.000Z'), "open": 180.24, "high": 181.75, "low": 176.53, "close": 178.88, "volume": 2875169 },
{ "date": new Date('2026-07-10T00:00:00.000Z'), "open": 178.88, "high": 180.17, "low": 178.39, "close": 180.16, "volume": 1771891 },
{ "date": new Date('2026-07-11T00:00:00.000Z'), "open": 180.16, "high": 182.25, "low": 178.11, "close": 178.34, "volume": 1760700 },
{ "date": new Date('2026-07-12T00:00:00.000Z'), "open": 178.34, "high": 183.67, "low": 175.68, "close": 181.53, "volume": 2986133 },
{ "date": new Date('2026-07-13T00:00:00.000Z'), "open": 181.53, "high": 183.06, "low": 178.25, "close": 180.7, "volume": 2754332 },
{ "date": new Date('2026-07-14T00:00:00.000Z'), "open": 180.7, "high": 182.04, "low": 178.8, "close": 181.02, "volume": 2853710 },
{ "date": new Date('2026-07-15T00:00:00.000Z'), "open": 181.02, "high": 184.6, "low": 178.5, "close": 182.81, "volume": 3309967 },
{ "date": new Date('2026-07-16T00:00:00.000Z'), "open": 182.81, "high": 187.85, "low": 180.39, "close": 185.86, "volume": 2219317 },
{ "date": new Date('2026-07-17T00:00:00.000Z'), "open": 185.86, "high": 186.1, "low": 181.67, "close": 184.07, "volume": 2014204 },
{ "date": new Date('2026-07-18T00:00:00.000Z'), "open": 184.07, "high": 185.04, "low": 180.87, "close": 182.15, "volume": 2597964 },
{ "date": new Date('2026-07-19T00:00:00.000Z'), "open": 182.15, "high": 185.62, "low": 181.28, "close": 182.95, "volume": 1855149 },
{ "date": new Date('2026-07-20T00:00:00.000Z'), "open": 182.95, "high": 184.31, "low": 179.38, "close": 180.08, "volume": 3538359 },
{ "date": new Date('2026-07-21T00:00:00.000Z'), "open": 180.08, "high": 183.87, "low": 178.35, "close": 182.21, "volume": 2111130 },
{ "date": new Date('2026-07-22T00:00:00.000Z'), "open": 182.21, "high": 183.77, "low": 179.79, "close": 182.59, "volume": 2470964 },
{ "date": new Date('2026-07-23T00:00:00.000Z'), "open": 182.59, "high": 185.11, "low": 178.74, "close": 180, "volume": 2215306 },
{ "date": new Date('2026-07-24T00:00:00.000Z'), "open": 180, "high": 182.37, "low": 179.22, "close": 181.3, "volume": 1930100 },
{ "date": new Date('2026-07-25T00:00:00.000Z'), "open": 181.3, "high": 182.29, "low": 176.78, "close": 179.41, "volume": 2564712 },
{ "date": new Date('2026-07-26T00:00:00.000Z'), "open": 179.41, "high": 181.57, "low": 176.8, "close": 179.78, "volume": 2695389 },
{ "date": new Date('2026-07-27T00:00:00.000Z'), "open": 179.78, "high": 183.37, "low": 177.65, "close": 182.53, "volume": 2612169 },
{ "date": new Date('2026-07-28T00:00:00.000Z'), "open": 182.53, "high": 185.98, "low": 180.64, "close": 185.06, "volume": 2871046 },
{ "date": new Date('2026-07-29T00:00:00.000Z'), "open": 185.06, "high": 185.86, "low": 180.35, "close": 182.69, "volume": 1950375 },
{ "date": new Date('2026-07-30T00:00:00.000Z'), "open": 182.69, "high": 185.15, "low": 177.55, "close": 180.14, "volume": 3537483 },
{ "date": new Date('2026-07-31T00:00:00.000Z'), "open": 180.14, "high": 180.56, "low": 178.7, "close": 179.29, "volume": 3027806 },
{ "date": new Date('2026-08-01T00:00:00.000Z'), "open": 179.29, "high": 183.63, "low": 178.43, "close": 181.63, "volume": 2848629 },
{ "date": new Date('2026-08-02T00:00:00.000Z'), "open": 181.63, "high": 185.46, "low": 179.23, "close": 182.99, "volume": 2719123 },
{ "date": new Date('2026-08-03T00:00:00.000Z'), "open": 182.99, "high": 183.03, "low": 181.76, "close": 181.94, "volume": 2892428 },
{ "date": new Date('2026-08-04T00:00:00.000Z'), "open": 181.94, "high": 184.62, "low": 181.8, "close": 182.87, "volume": 3059787 },
{ "date": new Date('2026-08-05T00:00:00.000Z'), "open": 182.87, "high": 183.86, "low": 179.61, "close": 180.65, "volume": 3153744 },
{ "date": new Date('2026-08-06T00:00:00.000Z'), "open": 180.65, "high": 183.48, "low": 180.36, "close": 183.38, "volume": 2096144 },
{ "date": new Date('2026-08-07T00:00:00.000Z'), "open": 183.38, "high": 183.72, "low": 179.24, "close": 181.35, "volume": 2428129 },
{ "date": new Date('2026-08-08T00:00:00.000Z'), "open": 181.35, "high": 183.15, "low": 178.87, "close": 181.68, "volume": 1957201 },
{ "date": new Date('2026-08-09T00:00:00.000Z'), "open": 181.68, "high": 184.48, "low": 180.15, "close": 184.09, "volume": 3131278 },
{ "date": new Date('2026-08-10T00:00:00.000Z'), "open": 184.09, "high": 187.25, "low": 182.16, "close": 184.76, "volume": 1986018 },
{ "date": new Date('2026-08-11T00:00:00.000Z'), "open": 184.76, "high": 185.27, "low": 181.34, "close": 184.06, "volume": 2629438 },
{ "date": new Date('2026-08-12T00:00:00.000Z'), "open": 184.06, "high": 185.48, "low": 181.89, "close": 182.38, "volume": 2086285 },
{ "date": new Date('2026-08-13T00:00:00.000Z'), "open": 182.38, "high": 185.11, "low": 180.61, "close": 183.66, "volume": 2860446 },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "open": 183.66, "high": 184.63, "low": 180.29, "close": 181.67, "volume": 2398495 },
{ "date": new Date('2026-08-15T00:00:00.000Z'), "open": 181.67, "high": 185.05, "low": 179.28, "close": 184.46, "volume": 2448935 },
{ "date": new Date('2026-08-16T00:00:00.000Z'), "open": 184.46, "high": 187.8, "low": 182.88, "close": 186.13, "volume": 2425201 },
{ "date": new Date('2026-08-17T00:00:00.000Z'), "open": 186.13, "high": 188.94, "low": 184.01, "close": 184.01, "volume": 2897024 },
{ "date": new Date('2026-08-18T00:00:00.000Z'), "open": 184.01, "high": 185.14, "low": 181.96, "close": 185.05, "volume": 2346585 },
{ "date": new Date('2026-08-19T00:00:00.000Z'), "open": 185.05, "high": 187.56, "low": 181.6, "close": 183.2, "volume": 1782162 },
{ "date": new Date('2026-08-20T00:00:00.000Z'), "open": 183.2, "high": 183.37, "low": 181.1, "close": 182.24, "volume": 3222334 },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "open": 182.24, "high": 187.12, "low": 180.33, "close": 184.51, "volume": 2058942 },
{ "date": new Date('2026-08-22T00:00:00.000Z'), "open": 184.51, "high": 187.36, "low": 184.49, "close": 186.44, "volume": 1849602 },
{ "date": new Date('2026-08-23T00:00:00.000Z'), "open": 186.44, "high": 189.61, "low": 183.73, "close": 188.9, "volume": 1968815 },
{ "date": new Date('2026-08-24T00:00:00.000Z'), "open": 188.9, "high": 192.67, "low": 188.31, "close": 191.85, "volume": 3047593 },
{ "date": new Date('2026-08-25T00:00:00.000Z'), "open": 191.85, "high": 194.69, "low": 188.25, "close": 190.53, "volume": 1890866 },
{ "date": new Date('2026-08-26T00:00:00.000Z'), "open": 190.53, "high": 192.03, "low": 188.23, "close": 190.78, "volume": 1826419 },
{ "date": new Date('2026-08-27T00:00:00.000Z'), "open": 190.78, "high": 196.36, "low": 190.07, "close": 193.85, "volume": 2686171 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "open": 193.85, "high": 197.11, "low": 192.05, "close": 194.2, "volume": 2566984 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "open": 194.2, "high": 194.38, "low": 191.92, "close": 192.45, "volume": 2585676 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "open": 192.45, "high": 192.6, "low": 190.83, "close": 191.48, "volume": 2902453 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "open": 191.48, "high": 195.18, "low": 190.07, "close": 194.15, "volume": 2226035 },
{ "date": new Date('2026-09-01T00:00:00.000Z'), "open": 194.15, "high": 194.96, "low": 191.2, "close": 194.68, "volume": 2865378 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "open": 194.68, "high": 195.97, "low": 191.95, "close": 192.18, "volume": 3179562 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "open": 192.18, "high": 197.54, "low": 190.1, "close": 195.29, "volume": 2203328 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "open": 195.29, "high": 200.11, "low": 193.34, "close": 197.72, "volume": 3287887 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "open": 197.72, "high": 202.47, "low": 196.55, "close": 200.86, "volume": 2108982 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "open": 200.86, "high": 202.44, "low": 200.14, "close": 201.7, "volume": 3050788 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "open": 201.7, "high": 206.09, "low": 201.08, "close": 203.76, "volume": 3160303 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "open": 203.76, "high": 205.09, "low": 203.28, "close": 203.62, "volume": 1547552 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "open": 203.62, "high": 206.45, "low": 199.93, "close": 200.54, "volume": 2419421 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "open": 200.54, "high": 203.41, "low": 196.4, "close": 199.31, "volume": 2137922 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "open": 199.31, "high": 201.44, "low": 197.01, "close": 197.94, "volume": 2856143 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "open": 197.94, "high": 200.87, "low": 193.01, "close": 195.54, "volume": 2016849 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "open": 195.54, "high": 197.51, "low": 192.95, "close": 196.79, "volume": 2621817 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "open": 196.79, "high": 199.2, "low": 194.82, "close": 197.52, "volume": 3033046 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "open": 197.52, "high": 203.69, "low": 197, "close": 200.66, "volume": 3041051 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "open": 200.66, "high": 204.11, "low": 198.61, "close": 203.59, "volume": 2082501 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "open": 203.59, "high": 208.28, "low": 201.87, "close": 205.27, "volume": 3222974 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "open": 205.27, "high": 206.64, "low": 203, "close": 203.49, "volume": 2462821 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "open": 203.49, "high": 204.33, "low": 198.71, "close": 200.51, "volume": 2368043 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "open": 200.51, "high": 204.21, "low": 199.53, "close": 204.04, "volume": 2964809 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "open": 204.04, "high": 205.6, "low": 199.82, "close": 201.65, "volume": 3263425 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "open": 201.65, "high": 206.26, "low": 198.81, "close": 203.2, "volume": 3180001 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "open": 203.2, "high": 206.48, "low": 200.12, "close": 205.46, "volume": 2041039 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "open": 205.46, "high": 208.24, "low": 202.34, "close": 203.24, "volume": 2468141 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "open": 203.24, "high": 206, "low": 202.82, "close": 205.56, "volume": 2886985 },
] },
];
export function Example() {
return (
);
}
```
#### Bollinger bands
A 20-period average with a band two deviations either side, over hollow candles.
```tsx
'use client';
import { IndicatorChartCard } from '@lilt-ui/charts/finance';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This period", "data": [
{ "date": new Date('2026-06-28T00:00:00.000Z'), "open": 175.33, "high": 180.25, "low": 174.18, "close": 178.33, "volume": 3702584 },
{ "date": new Date('2026-06-29T00:00:00.000Z'), "open": 178.33, "high": 178.83, "low": 175.83, "close": 176.69, "volume": 2561676 },
{ "date": new Date('2026-06-30T00:00:00.000Z'), "open": 176.69, "high": 178.45, "low": 175.77, "close": 176.71, "volume": 1691710 },
{ "date": new Date('2026-07-01T00:00:00.000Z'), "open": 176.71, "high": 177.68, "low": 174.58, "close": 175.69, "volume": 1891064 },
{ "date": new Date('2026-07-02T00:00:00.000Z'), "open": 175.69, "high": 176.87, "low": 172.86, "close": 175.31, "volume": 1862025 },
{ "date": new Date('2026-07-03T00:00:00.000Z'), "open": 175.31, "high": 178.66, "low": 173.7, "close": 178.41, "volume": 2873801 },
{ "date": new Date('2026-07-04T00:00:00.000Z'), "open": 178.41, "high": 181.32, "low": 176.93, "close": 179.67, "volume": 2917261 },
{ "date": new Date('2026-07-05T00:00:00.000Z'), "open": 179.67, "high": 182.32, "low": 176.74, "close": 178.41, "volume": 1924836 },
{ "date": new Date('2026-07-06T00:00:00.000Z'), "open": 178.41, "high": 182.22, "low": 175.89, "close": 181.04, "volume": 2601632 },
{ "date": new Date('2026-07-07T00:00:00.000Z'), "open": 181.04, "high": 181.73, "low": 177.68, "close": 178.74, "volume": 2747583 },
{ "date": new Date('2026-07-08T00:00:00.000Z'), "open": 178.74, "high": 180.38, "low": 176.15, "close": 180.24, "volume": 1829364 },
{ "date": new Date('2026-07-09T00:00:00.000Z'), "open": 180.24, "high": 181.75, "low": 176.53, "close": 178.88, "volume": 2875169 },
{ "date": new Date('2026-07-10T00:00:00.000Z'), "open": 178.88, "high": 180.17, "low": 178.39, "close": 180.16, "volume": 1771891 },
{ "date": new Date('2026-07-11T00:00:00.000Z'), "open": 180.16, "high": 182.25, "low": 178.11, "close": 178.34, "volume": 1760700 },
{ "date": new Date('2026-07-12T00:00:00.000Z'), "open": 178.34, "high": 183.67, "low": 175.68, "close": 181.53, "volume": 2986133 },
{ "date": new Date('2026-07-13T00:00:00.000Z'), "open": 181.53, "high": 183.06, "low": 178.25, "close": 180.7, "volume": 2754332 },
{ "date": new Date('2026-07-14T00:00:00.000Z'), "open": 180.7, "high": 182.04, "low": 178.8, "close": 181.02, "volume": 2853710 },
{ "date": new Date('2026-07-15T00:00:00.000Z'), "open": 181.02, "high": 184.6, "low": 178.5, "close": 182.81, "volume": 3309967 },
{ "date": new Date('2026-07-16T00:00:00.000Z'), "open": 182.81, "high": 187.85, "low": 180.39, "close": 185.86, "volume": 2219317 },
{ "date": new Date('2026-07-17T00:00:00.000Z'), "open": 185.86, "high": 186.1, "low": 181.67, "close": 184.07, "volume": 2014204 },
{ "date": new Date('2026-07-18T00:00:00.000Z'), "open": 184.07, "high": 185.04, "low": 180.87, "close": 182.15, "volume": 2597964 },
{ "date": new Date('2026-07-19T00:00:00.000Z'), "open": 182.15, "high": 185.62, "low": 181.28, "close": 182.95, "volume": 1855149 },
{ "date": new Date('2026-07-20T00:00:00.000Z'), "open": 182.95, "high": 184.31, "low": 179.38, "close": 180.08, "volume": 3538359 },
{ "date": new Date('2026-07-21T00:00:00.000Z'), "open": 180.08, "high": 183.87, "low": 178.35, "close": 182.21, "volume": 2111130 },
{ "date": new Date('2026-07-22T00:00:00.000Z'), "open": 182.21, "high": 183.77, "low": 179.79, "close": 182.59, "volume": 2470964 },
{ "date": new Date('2026-07-23T00:00:00.000Z'), "open": 182.59, "high": 185.11, "low": 178.74, "close": 180, "volume": 2215306 },
{ "date": new Date('2026-07-24T00:00:00.000Z'), "open": 180, "high": 182.37, "low": 179.22, "close": 181.3, "volume": 1930100 },
{ "date": new Date('2026-07-25T00:00:00.000Z'), "open": 181.3, "high": 182.29, "low": 176.78, "close": 179.41, "volume": 2564712 },
{ "date": new Date('2026-07-26T00:00:00.000Z'), "open": 179.41, "high": 181.57, "low": 176.8, "close": 179.78, "volume": 2695389 },
{ "date": new Date('2026-07-27T00:00:00.000Z'), "open": 179.78, "high": 183.37, "low": 177.65, "close": 182.53, "volume": 2612169 },
{ "date": new Date('2026-07-28T00:00:00.000Z'), "open": 182.53, "high": 185.98, "low": 180.64, "close": 185.06, "volume": 2871046 },
{ "date": new Date('2026-07-29T00:00:00.000Z'), "open": 185.06, "high": 185.86, "low": 180.35, "close": 182.69, "volume": 1950375 },
{ "date": new Date('2026-07-30T00:00:00.000Z'), "open": 182.69, "high": 185.15, "low": 177.55, "close": 180.14, "volume": 3537483 },
{ "date": new Date('2026-07-31T00:00:00.000Z'), "open": 180.14, "high": 180.56, "low": 178.7, "close": 179.29, "volume": 3027806 },
{ "date": new Date('2026-08-01T00:00:00.000Z'), "open": 179.29, "high": 183.63, "low": 178.43, "close": 181.63, "volume": 2848629 },
{ "date": new Date('2026-08-02T00:00:00.000Z'), "open": 181.63, "high": 185.46, "low": 179.23, "close": 182.99, "volume": 2719123 },
{ "date": new Date('2026-08-03T00:00:00.000Z'), "open": 182.99, "high": 183.03, "low": 181.76, "close": 181.94, "volume": 2892428 },
{ "date": new Date('2026-08-04T00:00:00.000Z'), "open": 181.94, "high": 184.62, "low": 181.8, "close": 182.87, "volume": 3059787 },
{ "date": new Date('2026-08-05T00:00:00.000Z'), "open": 182.87, "high": 183.86, "low": 179.61, "close": 180.65, "volume": 3153744 },
{ "date": new Date('2026-08-06T00:00:00.000Z'), "open": 180.65, "high": 183.48, "low": 180.36, "close": 183.38, "volume": 2096144 },
{ "date": new Date('2026-08-07T00:00:00.000Z'), "open": 183.38, "high": 183.72, "low": 179.24, "close": 181.35, "volume": 2428129 },
{ "date": new Date('2026-08-08T00:00:00.000Z'), "open": 181.35, "high": 183.15, "low": 178.87, "close": 181.68, "volume": 1957201 },
{ "date": new Date('2026-08-09T00:00:00.000Z'), "open": 181.68, "high": 184.48, "low": 180.15, "close": 184.09, "volume": 3131278 },
{ "date": new Date('2026-08-10T00:00:00.000Z'), "open": 184.09, "high": 187.25, "low": 182.16, "close": 184.76, "volume": 1986018 },
{ "date": new Date('2026-08-11T00:00:00.000Z'), "open": 184.76, "high": 185.27, "low": 181.34, "close": 184.06, "volume": 2629438 },
{ "date": new Date('2026-08-12T00:00:00.000Z'), "open": 184.06, "high": 185.48, "low": 181.89, "close": 182.38, "volume": 2086285 },
{ "date": new Date('2026-08-13T00:00:00.000Z'), "open": 182.38, "high": 185.11, "low": 180.61, "close": 183.66, "volume": 2860446 },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "open": 183.66, "high": 184.63, "low": 180.29, "close": 181.67, "volume": 2398495 },
{ "date": new Date('2026-08-15T00:00:00.000Z'), "open": 181.67, "high": 185.05, "low": 179.28, "close": 184.46, "volume": 2448935 },
{ "date": new Date('2026-08-16T00:00:00.000Z'), "open": 184.46, "high": 187.8, "low": 182.88, "close": 186.13, "volume": 2425201 },
{ "date": new Date('2026-08-17T00:00:00.000Z'), "open": 186.13, "high": 188.94, "low": 184.01, "close": 184.01, "volume": 2897024 },
{ "date": new Date('2026-08-18T00:00:00.000Z'), "open": 184.01, "high": 185.14, "low": 181.96, "close": 185.05, "volume": 2346585 },
{ "date": new Date('2026-08-19T00:00:00.000Z'), "open": 185.05, "high": 187.56, "low": 181.6, "close": 183.2, "volume": 1782162 },
{ "date": new Date('2026-08-20T00:00:00.000Z'), "open": 183.2, "high": 183.37, "low": 181.1, "close": 182.24, "volume": 3222334 },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "open": 182.24, "high": 187.12, "low": 180.33, "close": 184.51, "volume": 2058942 },
{ "date": new Date('2026-08-22T00:00:00.000Z'), "open": 184.51, "high": 187.36, "low": 184.49, "close": 186.44, "volume": 1849602 },
{ "date": new Date('2026-08-23T00:00:00.000Z'), "open": 186.44, "high": 189.61, "low": 183.73, "close": 188.9, "volume": 1968815 },
{ "date": new Date('2026-08-24T00:00:00.000Z'), "open": 188.9, "high": 192.67, "low": 188.31, "close": 191.85, "volume": 3047593 },
{ "date": new Date('2026-08-25T00:00:00.000Z'), "open": 191.85, "high": 194.69, "low": 188.25, "close": 190.53, "volume": 1890866 },
{ "date": new Date('2026-08-26T00:00:00.000Z'), "open": 190.53, "high": 192.03, "low": 188.23, "close": 190.78, "volume": 1826419 },
{ "date": new Date('2026-08-27T00:00:00.000Z'), "open": 190.78, "high": 196.36, "low": 190.07, "close": 193.85, "volume": 2686171 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "open": 193.85, "high": 197.11, "low": 192.05, "close": 194.2, "volume": 2566984 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "open": 194.2, "high": 194.38, "low": 191.92, "close": 192.45, "volume": 2585676 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "open": 192.45, "high": 192.6, "low": 190.83, "close": 191.48, "volume": 2902453 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "open": 191.48, "high": 195.18, "low": 190.07, "close": 194.15, "volume": 2226035 },
{ "date": new Date('2026-09-01T00:00:00.000Z'), "open": 194.15, "high": 194.96, "low": 191.2, "close": 194.68, "volume": 2865378 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "open": 194.68, "high": 195.97, "low": 191.95, "close": 192.18, "volume": 3179562 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "open": 192.18, "high": 197.54, "low": 190.1, "close": 195.29, "volume": 2203328 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "open": 195.29, "high": 200.11, "low": 193.34, "close": 197.72, "volume": 3287887 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "open": 197.72, "high": 202.47, "low": 196.55, "close": 200.86, "volume": 2108982 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "open": 200.86, "high": 202.44, "low": 200.14, "close": 201.7, "volume": 3050788 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "open": 201.7, "high": 206.09, "low": 201.08, "close": 203.76, "volume": 3160303 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "open": 203.76, "high": 205.09, "low": 203.28, "close": 203.62, "volume": 1547552 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "open": 203.62, "high": 206.45, "low": 199.93, "close": 200.54, "volume": 2419421 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "open": 200.54, "high": 203.41, "low": 196.4, "close": 199.31, "volume": 2137922 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "open": 199.31, "high": 201.44, "low": 197.01, "close": 197.94, "volume": 2856143 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "open": 197.94, "high": 200.87, "low": 193.01, "close": 195.54, "volume": 2016849 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "open": 195.54, "high": 197.51, "low": 192.95, "close": 196.79, "volume": 2621817 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "open": 196.79, "high": 199.2, "low": 194.82, "close": 197.52, "volume": 3033046 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "open": 197.52, "high": 203.69, "low": 197, "close": 200.66, "volume": 3041051 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "open": 200.66, "high": 204.11, "low": 198.61, "close": 203.59, "volume": 2082501 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "open": 203.59, "high": 208.28, "low": 201.87, "close": 205.27, "volume": 3222974 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "open": 205.27, "high": 206.64, "low": 203, "close": 203.49, "volume": 2462821 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "open": 203.49, "high": 204.33, "low": 198.71, "close": 200.51, "volume": 2368043 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "open": 200.51, "high": 204.21, "low": 199.53, "close": 204.04, "volume": 2964809 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "open": 204.04, "high": 205.6, "low": 199.82, "close": 201.65, "volume": 3263425 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "open": 201.65, "high": 206.26, "low": 198.81, "close": 203.2, "volume": 3180001 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "open": 203.2, "high": 206.48, "low": 200.12, "close": 205.46, "volume": 2041039 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "open": 205.46, "high": 208.24, "low": 202.34, "close": 203.24, "volume": 2468141 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "open": 203.24, "high": 206, "low": 202.82, "close": 205.56, "volume": 2886985 },
] },
{ "id": "previous", "label": "Last period", "data": [
{ "date": new Date('2026-03-30T00:00:00.000Z'), "open": 147.28, "high": 151.41, "low": 146.31, "close": 149.8, "volume": 3110171 },
{ "date": new Date('2026-03-31T00:00:00.000Z'), "open": 165.26, "high": 165.73, "low": 162.95, "close": 163.74, "volume": 2373957 },
{ "date": new Date('2026-04-01T00:00:00.000Z'), "open": 156.62, "high": 158.18, "low": 155.8, "close": 156.63, "volume": 1499523 },
{ "date": new Date('2026-04-02T00:00:00.000Z'), "open": 137.5, "high": 138.25, "low": 135.84, "close": 136.7, "volume": 1471439 },
{ "date": new Date('2026-04-03T00:00:00.000Z'), "open": 133.61, "high": 134.51, "low": 131.46, "close": 133.32, "volume": 1416050 },
{ "date": new Date('2026-04-04T00:00:00.000Z'), "open": 150.65, "high": 153.53, "low": 149.3, "close": 153.32, "volume": 2469632 },
{ "date": new Date('2026-04-05T00:00:00.000Z'), "open": 165.9, "high": 168.6, "low": 164.52, "close": 167.07, "volume": 2712670 },
{ "date": new Date('2026-04-06T00:00:00.000Z'), "open": 156.08, "high": 158.38, "low": 153.54, "close": 154.99, "volume": 1672141 },
{ "date": new Date('2026-04-07T00:00:00.000Z'), "open": 136.57, "high": 139.49, "low": 134.64, "close": 138.59, "volume": 1991538 },
{ "date": new Date('2026-04-08T00:00:00.000Z'), "open": 139.66, "high": 140.19, "low": 137.07, "close": 137.88, "volume": 2119545 },
{ "date": new Date('2026-04-09T00:00:00.000Z'), "open": 156.9, "high": 158.34, "low": 154.63, "close": 158.22, "volume": 1605843 },
{ "date": new Date('2026-04-10T00:00:00.000Z'), "open": 167.41, "high": 168.81, "low": 163.96, "close": 166.15, "volume": 2670484 },
{ "date": new Date('2026-04-11T00:00:00.000Z'), "open": 151.99, "high": 153.09, "low": 151.58, "close": 153.08, "volume": 1505572 },
{ "date": new Date('2026-04-12T00:00:00.000Z'), "open": 136.27, "high": 137.85, "low": 134.72, "close": 134.89, "volume": 1331756 },
{ "date": new Date('2026-04-13T00:00:00.000Z'), "open": 140.1, "high": 144.28, "low": 138.01, "close": 142.6, "volume": 2345802 },
{ "date": new Date('2026-04-14T00:00:00.000Z'), "open": 162.38, "high": 163.75, "low": 159.44, "close": 161.6, "volume": 2463746 },
{ "date": new Date('2026-04-15T00:00:00.000Z'), "open": 166.9, "high": 168.13, "low": 165.1, "close": 167.19, "volume": 2635663 },
{ "date": new Date('2026-04-16T00:00:00.000Z'), "open": 150.29, "high": 153.3, "low": 148.2, "close": 151.77, "volume": 2748010 },
{ "date": new Date('2026-04-17T00:00:00.000Z'), "open": 137.32, "high": 141.11, "low": 135.5, "close": 139.61, "volume": 1667101 },
{ "date": new Date('2026-04-18T00:00:00.000Z'), "open": 149.11, "high": 149.3, "low": 145.75, "close": 147.67, "volume": 1615910 },
{ "date": new Date('2026-04-19T00:00:00.000Z'), "open": 167.25, "high": 168.13, "low": 164.34, "close": 165.51, "volume": 2360589 },
{ "date": new Date('2026-04-20T00:00:00.000Z'), "open": 166.57, "high": 169.74, "low": 165.77, "close": 167.3, "volume": 1696459 },
{ "date": new Date('2026-04-21T00:00:00.000Z'), "open": 148.41, "high": 149.51, "low": 145.51, "close": 146.08, "volume": 2870336 },
{ "date": new Date('2026-04-22T00:00:00.000Z'), "open": 135.08, "high": 137.93, "low": 133.79, "close": 136.68, "volume": 1583633 },
{ "date": new Date('2026-04-23T00:00:00.000Z'), "open": 149.54, "high": 150.82, "low": 147.56, "close": 149.85, "volume": 2027963 },
{ "date": new Date('2026-04-24T00:00:00.000Z'), "open": 167.9, "high": 170.22, "low": 164.36, "close": 166, "volume": 2037081 },
{ "date": new Date('2026-04-25T00:00:00.000Z'), "open": 162, "high": 164.47, "low": 161.63, "close": 163.5, "volume": 1740643 },
{ "date": new Date('2026-04-26T00:00:00.000Z'), "open": 143.9, "high": 144.65, "low": 140.28, "close": 142.37, "volume": 2035192 },
{ "date": new Date('2026-04-27T00:00:00.000Z'), "open": 135.15, "high": 136.78, "low": 133.2, "close": 135.43, "volume": 2030440 },
{ "date": new Date('2026-04-28T00:00:00.000Z'), "open": 151.03, "high": 154.05, "low": 149.24, "close": 153.34, "volume": 2194431 },
{ "date": new Date('2026-04-29T00:00:00.000Z'), "open": 169.16, "high": 172.36, "low": 167.41, "close": 171.5, "volume": 2660718 },
{ "date": new Date('2026-04-30T00:00:00.000Z'), "open": 164.02, "high": 164.73, "low": 159.85, "close": 161.92, "volume": 1728669 },
{ "date": new Date('2026-05-01T00:00:00.000Z'), "open": 142.14, "high": 144.05, "low": 138.14, "close": 140.16, "volume": 2752314 },
{ "date": new Date('2026-05-02T00:00:00.000Z'), "open": 137, "high": 137.32, "low": 135.9, "close": 136.35, "volume": 2302727 },
{ "date": new Date('2026-05-03T00:00:00.000Z'), "open": 154.09, "high": 157.82, "low": 153.35, "close": 156.1, "volume": 2448222 },
{ "date": new Date('2026-05-04T00:00:00.000Z'), "open": 168.89, "high": 172.45, "low": 166.66, "close": 170.16, "volume": 2528440 },
{ "date": new Date('2026-05-05T00:00:00.000Z'), "open": 158.95, "high": 158.99, "low": 157.88, "close": 158.04, "volume": 2512488 },
{ "date": new Date('2026-05-06T00:00:00.000Z'), "open": 139.27, "high": 141.32, "low": 139.2, "close": 139.98, "volume": 2342116 },
{ "date": new Date('2026-05-07T00:00:00.000Z'), "open": 141.08, "high": 141.84, "low": 138.56, "close": 139.37, "volume": 2433029 },
{ "date": new Date('2026-05-08T00:00:00.000Z'), "open": 158.59, "high": 161.07, "low": 158.34, "close": 160.99, "volume": 1840179 },
{ "date": new Date('2026-05-09T00:00:00.000Z'), "open": 170.32, "high": 170.64, "low": 166.48, "close": 168.44, "volume": 2255238 },
{ "date": new Date('2026-05-10T00:00:00.000Z'), "open": 154.08, "high": 155.61, "low": 151.97, "close": 154.36, "volume": 1662874 },
{ "date": new Date('2026-05-11T00:00:00.000Z'), "open": 137.41, "high": 139.53, "low": 136.26, "close": 139.24, "volume": 2368340 },
{ "date": new Date('2026-05-12T00:00:00.000Z'), "open": 144.63, "high": 147.11, "low": 143.11, "close": 145.15, "volume": 1560273 },
{ "date": new Date('2026-05-13T00:00:00.000Z'), "open": 165.28, "high": 165.74, "low": 162.22, "close": 164.65, "volume": 2352196 },
{ "date": new Date('2026-05-14T00:00:00.000Z'), "open": 169.99, "high": 171.3, "low": 167.99, "close": 168.44, "volume": 1926813 },
{ "date": new Date('2026-05-15T00:00:00.000Z'), "open": 151.4, "high": 153.67, "low": 149.93, "close": 152.46, "volume": 2374580 },
{ "date": new Date('2026-05-16T00:00:00.000Z'), "open": 137.96, "high": 138.69, "low": 135.43, "close": 136.46, "volume": 1801665 },
{ "date": new Date('2026-05-17T00:00:00.000Z'), "open": 145.76, "high": 148.47, "low": 143.84, "close": 148, "volume": 1964854 },
{ "date": new Date('2026-05-18T00:00:00.000Z'), "open": 167.62, "high": 170.7, "low": 166.18, "close": 169.13, "volume": 2203736 },
{ "date": new Date('2026-05-19T00:00:00.000Z'), "open": 170.2, "high": 172.77, "low": 168.26, "close": 168.26, "volume": 2649081 },
{ "date": new Date('2026-05-20T00:00:00.000Z'), "open": 149.26, "high": 150.17, "low": 147.59, "close": 150.1, "volume": 1903385 },
{ "date": new Date('2026-05-21T00:00:00.000Z'), "open": 138.81, "high": 140.7, "low": 136.2, "close": 137.4, "volume": 1336871 },
{ "date": new Date('2026-05-22T00:00:00.000Z'), "open": 150.4, "high": 150.51, "low": 148.6, "close": 149.58, "volume": 2644877 },
{ "date": new Date('2026-05-23T00:00:00.000Z'), "open": 167.59, "high": 172.07, "low": 165.83, "close": 169.67, "volume": 1893374 },
{ "date": new Date('2026-05-24T00:00:00.000Z'), "open": 166.39, "high": 168.96, "low": 166.37, "close": 168.13, "volume": 1667939 },
{ "date": new Date('2026-05-25T00:00:00.000Z'), "open": 147.93, "high": 150.45, "low": 145.78, "close": 149.9, "volume": 1562192 },
{ "date": new Date('2026-05-26T00:00:00.000Z'), "open": 142.3, "high": 145.14, "low": 141.86, "close": 144.52, "volume": 2295821 },
{ "date": new Date('2026-05-27T00:00:00.000Z'), "open": 161.18, "high": 163.57, "low": 158.16, "close": 160.08, "volume": 1588630 },
{ "date": new Date('2026-05-28T00:00:00.000Z'), "open": 176.58, "high": 177.97, "low": 174.44, "close": 176.81, "volume": 1692657 },
{ "date": new Date('2026-05-29T00:00:00.000Z'), "open": 169.08, "high": 174.03, "low": 168.45, "close": 171.8, "volume": 2380641 },
{ "date": new Date('2026-05-30T00:00:00.000Z'), "open": 150.81, "high": 153.35, "low": 149.41, "close": 151.1, "volume": 1997075 },
{ "date": new Date('2026-05-31T00:00:00.000Z'), "open": 147.7, "high": 147.84, "low": 145.97, "close": 146.37, "volume": 1966572 },
{ "date": new Date('2026-06-01T00:00:00.000Z'), "open": 165.41, "high": 165.5, "low": 164.02, "close": 164.58, "volume": 2494707 },
{ "date": new Date('2026-06-02T00:00:00.000Z'), "open": 178.05, "high": 181.49, "low": 176.74, "close": 180.54, "volume": 2069940 },
{ "date": new Date('2026-06-03T00:00:00.000Z'), "open": 168.63, "high": 169.34, "low": 166.1, "close": 169.09, "volume": 2488774 },
{ "date": new Date('2026-06-04T00:00:00.000Z'), "open": 149.01, "high": 150, "low": 146.92, "close": 147.1, "volume": 2433656 },
{ "date": new Date('2026-06-05T00:00:00.000Z'), "open": 148.27, "high": 152.41, "low": 146.7, "close": 150.67, "volume": 1699923 },
{ "date": new Date('2026-06-06T00:00:00.000Z'), "open": 171.46, "high": 175.69, "low": 169.74, "close": 173.59, "volume": 2886633 },
{ "date": new Date('2026-06-07T00:00:00.000Z'), "open": 183.64, "high": 188.05, "low": 182.55, "close": 186.56, "volume": 1958788 },
{ "date": new Date('2026-06-08T00:00:00.000Z'), "open": 170.64, "high": 171.98, "low": 170.03, "close": 171.4, "volume": 2591763 },
{ "date": new Date('2026-06-09T00:00:00.000Z'), "open": 152.5, "high": 155.87, "low": 152.08, "close": 154.11, "volume": 2390200 },
{ "date": new Date('2026-06-10T00:00:00.000Z'), "open": 160.09, "high": 161.14, "low": 159.72, "close": 159.98, "volume": 1215900 },
{ "date": new Date('2026-06-11T00:00:00.000Z'), "open": 182.16, "high": 184.7, "low": 178.86, "close": 179.41, "volume": 2164476 },
{ "date": new Date('2026-06-12T00:00:00.000Z'), "open": 185.21, "high": 187.86, "low": 181.4, "close": 184.07, "volume": 1974440 },
{ "date": new Date('2026-06-13T00:00:00.000Z'), "open": 165.44, "high": 167.21, "low": 163.53, "close": 164.3, "volume": 2370781 },
{ "date": new Date('2026-06-14T00:00:00.000Z'), "open": 148.68, "high": 150.88, "low": 144.98, "close": 146.88, "volume": 1514960 },
{ "date": new Date('2026-06-15T00:00:00.000Z'), "open": 156.9, "high": 158.48, "low": 154.82, "close": 157.9, "volume": 2103753 },
{ "date": new Date('2026-06-16T00:00:00.000Z'), "open": 178.83, "high": 181, "low": 177.04, "close": 179.49, "volume": 2756231 },
{ "date": new Date('2026-06-17T00:00:00.000Z'), "open": 180.61, "high": 186.25, "low": 180, "close": 183.48, "volume": 2780645 },
{ "date": new Date('2026-06-18T00:00:00.000Z'), "open": 162.75, "high": 165.54, "low": 161.08, "close": 165.12, "volume": 1689021 },
{ "date": new Date('2026-06-19T00:00:00.000Z'), "open": 152.72, "high": 156.24, "low": 151.43, "close": 153.98, "volume": 2417696 },
{ "date": new Date('2026-06-20T00:00:00.000Z'), "open": 168.5, "high": 169.63, "low": 167, "close": 167.04, "volume": 2021664 },
{ "date": new Date('2026-06-21T00:00:00.000Z'), "open": 187.13, "high": 187.91, "low": 182.74, "close": 184.39, "volume": 2177707 },
{ "date": new Date('2026-06-22T00:00:00.000Z'), "open": 180.8, "high": 184.14, "low": 179.92, "close": 183.99, "volume": 2673441 },
{ "date": new Date('2026-06-23T00:00:00.000Z'), "open": 161.89, "high": 163.1, "low": 158.54, "close": 159.99, "volume": 2589200 },
{ "date": new Date('2026-06-24T00:00:00.000Z'), "open": 151.91, "high": 155.38, "low": 149.77, "close": 153.1, "volume": 2395635 },
{ "date": new Date('2026-06-25T00:00:00.000Z'), "open": 170.7, "high": 173.49, "low": 168.15, "close": 172.64, "volume": 1714962 },
{ "date": new Date('2026-06-26T00:00:00.000Z'), "open": 190.42, "high": 192.99, "low": 187.53, "close": 188.36, "volume": 2287434 },
{ "date": new Date('2026-06-27T00:00:00.000Z'), "open": 180.11, "high": 183, "low": 179.74, "close": 182.17, "volume": 2558416 },
] },
];
export function Example() {
return (
);
}
```
#### Line with volume
The close as a line with fast and slow averages, and volume under it instead of oscillators.
```tsx
'use client';
import { IndicatorChartCard } from '@lilt-ui/charts/finance';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This period", "data": [
{ "date": new Date('2026-06-28T00:00:00.000Z'), "open": 175.33, "high": 180.25, "low": 174.18, "close": 178.33, "volume": 3702584 },
{ "date": new Date('2026-06-29T00:00:00.000Z'), "open": 178.33, "high": 178.83, "low": 175.83, "close": 176.69, "volume": 2561676 },
{ "date": new Date('2026-06-30T00:00:00.000Z'), "open": 176.69, "high": 178.45, "low": 175.77, "close": 176.71, "volume": 1691710 },
{ "date": new Date('2026-07-01T00:00:00.000Z'), "open": 176.71, "high": 177.68, "low": 174.58, "close": 175.69, "volume": 1891064 },
{ "date": new Date('2026-07-02T00:00:00.000Z'), "open": 175.69, "high": 176.87, "low": 172.86, "close": 175.31, "volume": 1862025 },
{ "date": new Date('2026-07-03T00:00:00.000Z'), "open": 175.31, "high": 178.66, "low": 173.7, "close": 178.41, "volume": 2873801 },
{ "date": new Date('2026-07-04T00:00:00.000Z'), "open": 178.41, "high": 181.32, "low": 176.93, "close": 179.67, "volume": 2917261 },
{ "date": new Date('2026-07-05T00:00:00.000Z'), "open": 179.67, "high": 182.32, "low": 176.74, "close": 178.41, "volume": 1924836 },
{ "date": new Date('2026-07-06T00:00:00.000Z'), "open": 178.41, "high": 182.22, "low": 175.89, "close": 181.04, "volume": 2601632 },
{ "date": new Date('2026-07-07T00:00:00.000Z'), "open": 181.04, "high": 181.73, "low": 177.68, "close": 178.74, "volume": 2747583 },
{ "date": new Date('2026-07-08T00:00:00.000Z'), "open": 178.74, "high": 180.38, "low": 176.15, "close": 180.24, "volume": 1829364 },
{ "date": new Date('2026-07-09T00:00:00.000Z'), "open": 180.24, "high": 181.75, "low": 176.53, "close": 178.88, "volume": 2875169 },
{ "date": new Date('2026-07-10T00:00:00.000Z'), "open": 178.88, "high": 180.17, "low": 178.39, "close": 180.16, "volume": 1771891 },
{ "date": new Date('2026-07-11T00:00:00.000Z'), "open": 180.16, "high": 182.25, "low": 178.11, "close": 178.34, "volume": 1760700 },
{ "date": new Date('2026-07-12T00:00:00.000Z'), "open": 178.34, "high": 183.67, "low": 175.68, "close": 181.53, "volume": 2986133 },
{ "date": new Date('2026-07-13T00:00:00.000Z'), "open": 181.53, "high": 183.06, "low": 178.25, "close": 180.7, "volume": 2754332 },
{ "date": new Date('2026-07-14T00:00:00.000Z'), "open": 180.7, "high": 182.04, "low": 178.8, "close": 181.02, "volume": 2853710 },
{ "date": new Date('2026-07-15T00:00:00.000Z'), "open": 181.02, "high": 184.6, "low": 178.5, "close": 182.81, "volume": 3309967 },
{ "date": new Date('2026-07-16T00:00:00.000Z'), "open": 182.81, "high": 187.85, "low": 180.39, "close": 185.86, "volume": 2219317 },
{ "date": new Date('2026-07-17T00:00:00.000Z'), "open": 185.86, "high": 186.1, "low": 181.67, "close": 184.07, "volume": 2014204 },
{ "date": new Date('2026-07-18T00:00:00.000Z'), "open": 184.07, "high": 185.04, "low": 180.87, "close": 182.15, "volume": 2597964 },
{ "date": new Date('2026-07-19T00:00:00.000Z'), "open": 182.15, "high": 185.62, "low": 181.28, "close": 182.95, "volume": 1855149 },
{ "date": new Date('2026-07-20T00:00:00.000Z'), "open": 182.95, "high": 184.31, "low": 179.38, "close": 180.08, "volume": 3538359 },
{ "date": new Date('2026-07-21T00:00:00.000Z'), "open": 180.08, "high": 183.87, "low": 178.35, "close": 182.21, "volume": 2111130 },
{ "date": new Date('2026-07-22T00:00:00.000Z'), "open": 182.21, "high": 183.77, "low": 179.79, "close": 182.59, "volume": 2470964 },
{ "date": new Date('2026-07-23T00:00:00.000Z'), "open": 182.59, "high": 185.11, "low": 178.74, "close": 180, "volume": 2215306 },
{ "date": new Date('2026-07-24T00:00:00.000Z'), "open": 180, "high": 182.37, "low": 179.22, "close": 181.3, "volume": 1930100 },
{ "date": new Date('2026-07-25T00:00:00.000Z'), "open": 181.3, "high": 182.29, "low": 176.78, "close": 179.41, "volume": 2564712 },
{ "date": new Date('2026-07-26T00:00:00.000Z'), "open": 179.41, "high": 181.57, "low": 176.8, "close": 179.78, "volume": 2695389 },
{ "date": new Date('2026-07-27T00:00:00.000Z'), "open": 179.78, "high": 183.37, "low": 177.65, "close": 182.53, "volume": 2612169 },
{ "date": new Date('2026-07-28T00:00:00.000Z'), "open": 182.53, "high": 185.98, "low": 180.64, "close": 185.06, "volume": 2871046 },
{ "date": new Date('2026-07-29T00:00:00.000Z'), "open": 185.06, "high": 185.86, "low": 180.35, "close": 182.69, "volume": 1950375 },
{ "date": new Date('2026-07-30T00:00:00.000Z'), "open": 182.69, "high": 185.15, "low": 177.55, "close": 180.14, "volume": 3537483 },
{ "date": new Date('2026-07-31T00:00:00.000Z'), "open": 180.14, "high": 180.56, "low": 178.7, "close": 179.29, "volume": 3027806 },
{ "date": new Date('2026-08-01T00:00:00.000Z'), "open": 179.29, "high": 183.63, "low": 178.43, "close": 181.63, "volume": 2848629 },
{ "date": new Date('2026-08-02T00:00:00.000Z'), "open": 181.63, "high": 185.46, "low": 179.23, "close": 182.99, "volume": 2719123 },
{ "date": new Date('2026-08-03T00:00:00.000Z'), "open": 182.99, "high": 183.03, "low": 181.76, "close": 181.94, "volume": 2892428 },
{ "date": new Date('2026-08-04T00:00:00.000Z'), "open": 181.94, "high": 184.62, "low": 181.8, "close": 182.87, "volume": 3059787 },
{ "date": new Date('2026-08-05T00:00:00.000Z'), "open": 182.87, "high": 183.86, "low": 179.61, "close": 180.65, "volume": 3153744 },
{ "date": new Date('2026-08-06T00:00:00.000Z'), "open": 180.65, "high": 183.48, "low": 180.36, "close": 183.38, "volume": 2096144 },
{ "date": new Date('2026-08-07T00:00:00.000Z'), "open": 183.38, "high": 183.72, "low": 179.24, "close": 181.35, "volume": 2428129 },
{ "date": new Date('2026-08-08T00:00:00.000Z'), "open": 181.35, "high": 183.15, "low": 178.87, "close": 181.68, "volume": 1957201 },
{ "date": new Date('2026-08-09T00:00:00.000Z'), "open": 181.68, "high": 184.48, "low": 180.15, "close": 184.09, "volume": 3131278 },
{ "date": new Date('2026-08-10T00:00:00.000Z'), "open": 184.09, "high": 187.25, "low": 182.16, "close": 184.76, "volume": 1986018 },
{ "date": new Date('2026-08-11T00:00:00.000Z'), "open": 184.76, "high": 185.27, "low": 181.34, "close": 184.06, "volume": 2629438 },
{ "date": new Date('2026-08-12T00:00:00.000Z'), "open": 184.06, "high": 185.48, "low": 181.89, "close": 182.38, "volume": 2086285 },
{ "date": new Date('2026-08-13T00:00:00.000Z'), "open": 182.38, "high": 185.11, "low": 180.61, "close": 183.66, "volume": 2860446 },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "open": 183.66, "high": 184.63, "low": 180.29, "close": 181.67, "volume": 2398495 },
{ "date": new Date('2026-08-15T00:00:00.000Z'), "open": 181.67, "high": 185.05, "low": 179.28, "close": 184.46, "volume": 2448935 },
{ "date": new Date('2026-08-16T00:00:00.000Z'), "open": 184.46, "high": 187.8, "low": 182.88, "close": 186.13, "volume": 2425201 },
{ "date": new Date('2026-08-17T00:00:00.000Z'), "open": 186.13, "high": 188.94, "low": 184.01, "close": 184.01, "volume": 2897024 },
{ "date": new Date('2026-08-18T00:00:00.000Z'), "open": 184.01, "high": 185.14, "low": 181.96, "close": 185.05, "volume": 2346585 },
{ "date": new Date('2026-08-19T00:00:00.000Z'), "open": 185.05, "high": 187.56, "low": 181.6, "close": 183.2, "volume": 1782162 },
{ "date": new Date('2026-08-20T00:00:00.000Z'), "open": 183.2, "high": 183.37, "low": 181.1, "close": 182.24, "volume": 3222334 },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "open": 182.24, "high": 187.12, "low": 180.33, "close": 184.51, "volume": 2058942 },
{ "date": new Date('2026-08-22T00:00:00.000Z'), "open": 184.51, "high": 187.36, "low": 184.49, "close": 186.44, "volume": 1849602 },
{ "date": new Date('2026-08-23T00:00:00.000Z'), "open": 186.44, "high": 189.61, "low": 183.73, "close": 188.9, "volume": 1968815 },
{ "date": new Date('2026-08-24T00:00:00.000Z'), "open": 188.9, "high": 192.67, "low": 188.31, "close": 191.85, "volume": 3047593 },
{ "date": new Date('2026-08-25T00:00:00.000Z'), "open": 191.85, "high": 194.69, "low": 188.25, "close": 190.53, "volume": 1890866 },
{ "date": new Date('2026-08-26T00:00:00.000Z'), "open": 190.53, "high": 192.03, "low": 188.23, "close": 190.78, "volume": 1826419 },
{ "date": new Date('2026-08-27T00:00:00.000Z'), "open": 190.78, "high": 196.36, "low": 190.07, "close": 193.85, "volume": 2686171 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "open": 193.85, "high": 197.11, "low": 192.05, "close": 194.2, "volume": 2566984 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "open": 194.2, "high": 194.38, "low": 191.92, "close": 192.45, "volume": 2585676 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "open": 192.45, "high": 192.6, "low": 190.83, "close": 191.48, "volume": 2902453 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "open": 191.48, "high": 195.18, "low": 190.07, "close": 194.15, "volume": 2226035 },
{ "date": new Date('2026-09-01T00:00:00.000Z'), "open": 194.15, "high": 194.96, "low": 191.2, "close": 194.68, "volume": 2865378 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "open": 194.68, "high": 195.97, "low": 191.95, "close": 192.18, "volume": 3179562 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "open": 192.18, "high": 197.54, "low": 190.1, "close": 195.29, "volume": 2203328 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "open": 195.29, "high": 200.11, "low": 193.34, "close": 197.72, "volume": 3287887 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "open": 197.72, "high": 202.47, "low": 196.55, "close": 200.86, "volume": 2108982 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "open": 200.86, "high": 202.44, "low": 200.14, "close": 201.7, "volume": 3050788 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "open": 201.7, "high": 206.09, "low": 201.08, "close": 203.76, "volume": 3160303 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "open": 203.76, "high": 205.09, "low": 203.28, "close": 203.62, "volume": 1547552 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "open": 203.62, "high": 206.45, "low": 199.93, "close": 200.54, "volume": 2419421 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "open": 200.54, "high": 203.41, "low": 196.4, "close": 199.31, "volume": 2137922 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "open": 199.31, "high": 201.44, "low": 197.01, "close": 197.94, "volume": 2856143 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "open": 197.94, "high": 200.87, "low": 193.01, "close": 195.54, "volume": 2016849 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "open": 195.54, "high": 197.51, "low": 192.95, "close": 196.79, "volume": 2621817 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "open": 196.79, "high": 199.2, "low": 194.82, "close": 197.52, "volume": 3033046 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "open": 197.52, "high": 203.69, "low": 197, "close": 200.66, "volume": 3041051 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "open": 200.66, "high": 204.11, "low": 198.61, "close": 203.59, "volume": 2082501 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "open": 203.59, "high": 208.28, "low": 201.87, "close": 205.27, "volume": 3222974 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "open": 205.27, "high": 206.64, "low": 203, "close": 203.49, "volume": 2462821 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "open": 203.49, "high": 204.33, "low": 198.71, "close": 200.51, "volume": 2368043 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "open": 200.51, "high": 204.21, "low": 199.53, "close": 204.04, "volume": 2964809 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "open": 204.04, "high": 205.6, "low": 199.82, "close": 201.65, "volume": 3263425 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "open": 201.65, "high": 206.26, "low": 198.81, "close": 203.2, "volume": 3180001 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "open": 203.2, "high": 206.48, "low": 200.12, "close": 205.46, "volume": 2041039 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "open": 205.46, "high": 208.24, "low": 202.34, "close": 203.24, "volume": 2468141 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "open": 203.24, "high": 206, "low": 202.82, "close": 205.56, "volume": 2886985 },
] },
{ "id": "previous", "label": "Last period", "data": [
{ "date": new Date('2026-03-30T00:00:00.000Z'), "open": 147.28, "high": 151.41, "low": 146.31, "close": 149.8, "volume": 3110171 },
{ "date": new Date('2026-03-31T00:00:00.000Z'), "open": 165.26, "high": 165.73, "low": 162.95, "close": 163.74, "volume": 2373957 },
{ "date": new Date('2026-04-01T00:00:00.000Z'), "open": 156.62, "high": 158.18, "low": 155.8, "close": 156.63, "volume": 1499523 },
{ "date": new Date('2026-04-02T00:00:00.000Z'), "open": 137.5, "high": 138.25, "low": 135.84, "close": 136.7, "volume": 1471439 },
{ "date": new Date('2026-04-03T00:00:00.000Z'), "open": 133.61, "high": 134.51, "low": 131.46, "close": 133.32, "volume": 1416050 },
{ "date": new Date('2026-04-04T00:00:00.000Z'), "open": 150.65, "high": 153.53, "low": 149.3, "close": 153.32, "volume": 2469632 },
{ "date": new Date('2026-04-05T00:00:00.000Z'), "open": 165.9, "high": 168.6, "low": 164.52, "close": 167.07, "volume": 2712670 },
{ "date": new Date('2026-04-06T00:00:00.000Z'), "open": 156.08, "high": 158.38, "low": 153.54, "close": 154.99, "volume": 1672141 },
{ "date": new Date('2026-04-07T00:00:00.000Z'), "open": 136.57, "high": 139.49, "low": 134.64, "close": 138.59, "volume": 1991538 },
{ "date": new Date('2026-04-08T00:00:00.000Z'), "open": 139.66, "high": 140.19, "low": 137.07, "close": 137.88, "volume": 2119545 },
{ "date": new Date('2026-04-09T00:00:00.000Z'), "open": 156.9, "high": 158.34, "low": 154.63, "close": 158.22, "volume": 1605843 },
{ "date": new Date('2026-04-10T00:00:00.000Z'), "open": 167.41, "high": 168.81, "low": 163.96, "close": 166.15, "volume": 2670484 },
{ "date": new Date('2026-04-11T00:00:00.000Z'), "open": 151.99, "high": 153.09, "low": 151.58, "close": 153.08, "volume": 1505572 },
{ "date": new Date('2026-04-12T00:00:00.000Z'), "open": 136.27, "high": 137.85, "low": 134.72, "close": 134.89, "volume": 1331756 },
{ "date": new Date('2026-04-13T00:00:00.000Z'), "open": 140.1, "high": 144.28, "low": 138.01, "close": 142.6, "volume": 2345802 },
{ "date": new Date('2026-04-14T00:00:00.000Z'), "open": 162.38, "high": 163.75, "low": 159.44, "close": 161.6, "volume": 2463746 },
{ "date": new Date('2026-04-15T00:00:00.000Z'), "open": 166.9, "high": 168.13, "low": 165.1, "close": 167.19, "volume": 2635663 },
{ "date": new Date('2026-04-16T00:00:00.000Z'), "open": 150.29, "high": 153.3, "low": 148.2, "close": 151.77, "volume": 2748010 },
{ "date": new Date('2026-04-17T00:00:00.000Z'), "open": 137.32, "high": 141.11, "low": 135.5, "close": 139.61, "volume": 1667101 },
{ "date": new Date('2026-04-18T00:00:00.000Z'), "open": 149.11, "high": 149.3, "low": 145.75, "close": 147.67, "volume": 1615910 },
{ "date": new Date('2026-04-19T00:00:00.000Z'), "open": 167.25, "high": 168.13, "low": 164.34, "close": 165.51, "volume": 2360589 },
{ "date": new Date('2026-04-20T00:00:00.000Z'), "open": 166.57, "high": 169.74, "low": 165.77, "close": 167.3, "volume": 1696459 },
{ "date": new Date('2026-04-21T00:00:00.000Z'), "open": 148.41, "high": 149.51, "low": 145.51, "close": 146.08, "volume": 2870336 },
{ "date": new Date('2026-04-22T00:00:00.000Z'), "open": 135.08, "high": 137.93, "low": 133.79, "close": 136.68, "volume": 1583633 },
{ "date": new Date('2026-04-23T00:00:00.000Z'), "open": 149.54, "high": 150.82, "low": 147.56, "close": 149.85, "volume": 2027963 },
{ "date": new Date('2026-04-24T00:00:00.000Z'), "open": 167.9, "high": 170.22, "low": 164.36, "close": 166, "volume": 2037081 },
{ "date": new Date('2026-04-25T00:00:00.000Z'), "open": 162, "high": 164.47, "low": 161.63, "close": 163.5, "volume": 1740643 },
{ "date": new Date('2026-04-26T00:00:00.000Z'), "open": 143.9, "high": 144.65, "low": 140.28, "close": 142.37, "volume": 2035192 },
{ "date": new Date('2026-04-27T00:00:00.000Z'), "open": 135.15, "high": 136.78, "low": 133.2, "close": 135.43, "volume": 2030440 },
{ "date": new Date('2026-04-28T00:00:00.000Z'), "open": 151.03, "high": 154.05, "low": 149.24, "close": 153.34, "volume": 2194431 },
{ "date": new Date('2026-04-29T00:00:00.000Z'), "open": 169.16, "high": 172.36, "low": 167.41, "close": 171.5, "volume": 2660718 },
{ "date": new Date('2026-04-30T00:00:00.000Z'), "open": 164.02, "high": 164.73, "low": 159.85, "close": 161.92, "volume": 1728669 },
{ "date": new Date('2026-05-01T00:00:00.000Z'), "open": 142.14, "high": 144.05, "low": 138.14, "close": 140.16, "volume": 2752314 },
{ "date": new Date('2026-05-02T00:00:00.000Z'), "open": 137, "high": 137.32, "low": 135.9, "close": 136.35, "volume": 2302727 },
{ "date": new Date('2026-05-03T00:00:00.000Z'), "open": 154.09, "high": 157.82, "low": 153.35, "close": 156.1, "volume": 2448222 },
{ "date": new Date('2026-05-04T00:00:00.000Z'), "open": 168.89, "high": 172.45, "low": 166.66, "close": 170.16, "volume": 2528440 },
{ "date": new Date('2026-05-05T00:00:00.000Z'), "open": 158.95, "high": 158.99, "low": 157.88, "close": 158.04, "volume": 2512488 },
{ "date": new Date('2026-05-06T00:00:00.000Z'), "open": 139.27, "high": 141.32, "low": 139.2, "close": 139.98, "volume": 2342116 },
{ "date": new Date('2026-05-07T00:00:00.000Z'), "open": 141.08, "high": 141.84, "low": 138.56, "close": 139.37, "volume": 2433029 },
{ "date": new Date('2026-05-08T00:00:00.000Z'), "open": 158.59, "high": 161.07, "low": 158.34, "close": 160.99, "volume": 1840179 },
{ "date": new Date('2026-05-09T00:00:00.000Z'), "open": 170.32, "high": 170.64, "low": 166.48, "close": 168.44, "volume": 2255238 },
{ "date": new Date('2026-05-10T00:00:00.000Z'), "open": 154.08, "high": 155.61, "low": 151.97, "close": 154.36, "volume": 1662874 },
{ "date": new Date('2026-05-11T00:00:00.000Z'), "open": 137.41, "high": 139.53, "low": 136.26, "close": 139.24, "volume": 2368340 },
{ "date": new Date('2026-05-12T00:00:00.000Z'), "open": 144.63, "high": 147.11, "low": 143.11, "close": 145.15, "volume": 1560273 },
{ "date": new Date('2026-05-13T00:00:00.000Z'), "open": 165.28, "high": 165.74, "low": 162.22, "close": 164.65, "volume": 2352196 },
{ "date": new Date('2026-05-14T00:00:00.000Z'), "open": 169.99, "high": 171.3, "low": 167.99, "close": 168.44, "volume": 1926813 },
{ "date": new Date('2026-05-15T00:00:00.000Z'), "open": 151.4, "high": 153.67, "low": 149.93, "close": 152.46, "volume": 2374580 },
{ "date": new Date('2026-05-16T00:00:00.000Z'), "open": 137.96, "high": 138.69, "low": 135.43, "close": 136.46, "volume": 1801665 },
{ "date": new Date('2026-05-17T00:00:00.000Z'), "open": 145.76, "high": 148.47, "low": 143.84, "close": 148, "volume": 1964854 },
{ "date": new Date('2026-05-18T00:00:00.000Z'), "open": 167.62, "high": 170.7, "low": 166.18, "close": 169.13, "volume": 2203736 },
{ "date": new Date('2026-05-19T00:00:00.000Z'), "open": 170.2, "high": 172.77, "low": 168.26, "close": 168.26, "volume": 2649081 },
{ "date": new Date('2026-05-20T00:00:00.000Z'), "open": 149.26, "high": 150.17, "low": 147.59, "close": 150.1, "volume": 1903385 },
{ "date": new Date('2026-05-21T00:00:00.000Z'), "open": 138.81, "high": 140.7, "low": 136.2, "close": 137.4, "volume": 1336871 },
{ "date": new Date('2026-05-22T00:00:00.000Z'), "open": 150.4, "high": 150.51, "low": 148.6, "close": 149.58, "volume": 2644877 },
{ "date": new Date('2026-05-23T00:00:00.000Z'), "open": 167.59, "high": 172.07, "low": 165.83, "close": 169.67, "volume": 1893374 },
{ "date": new Date('2026-05-24T00:00:00.000Z'), "open": 166.39, "high": 168.96, "low": 166.37, "close": 168.13, "volume": 1667939 },
{ "date": new Date('2026-05-25T00:00:00.000Z'), "open": 147.93, "high": 150.45, "low": 145.78, "close": 149.9, "volume": 1562192 },
{ "date": new Date('2026-05-26T00:00:00.000Z'), "open": 142.3, "high": 145.14, "low": 141.86, "close": 144.52, "volume": 2295821 },
{ "date": new Date('2026-05-27T00:00:00.000Z'), "open": 161.18, "high": 163.57, "low": 158.16, "close": 160.08, "volume": 1588630 },
{ "date": new Date('2026-05-28T00:00:00.000Z'), "open": 176.58, "high": 177.97, "low": 174.44, "close": 176.81, "volume": 1692657 },
{ "date": new Date('2026-05-29T00:00:00.000Z'), "open": 169.08, "high": 174.03, "low": 168.45, "close": 171.8, "volume": 2380641 },
{ "date": new Date('2026-05-30T00:00:00.000Z'), "open": 150.81, "high": 153.35, "low": 149.41, "close": 151.1, "volume": 1997075 },
{ "date": new Date('2026-05-31T00:00:00.000Z'), "open": 147.7, "high": 147.84, "low": 145.97, "close": 146.37, "volume": 1966572 },
{ "date": new Date('2026-06-01T00:00:00.000Z'), "open": 165.41, "high": 165.5, "low": 164.02, "close": 164.58, "volume": 2494707 },
{ "date": new Date('2026-06-02T00:00:00.000Z'), "open": 178.05, "high": 181.49, "low": 176.74, "close": 180.54, "volume": 2069940 },
{ "date": new Date('2026-06-03T00:00:00.000Z'), "open": 168.63, "high": 169.34, "low": 166.1, "close": 169.09, "volume": 2488774 },
{ "date": new Date('2026-06-04T00:00:00.000Z'), "open": 149.01, "high": 150, "low": 146.92, "close": 147.1, "volume": 2433656 },
{ "date": new Date('2026-06-05T00:00:00.000Z'), "open": 148.27, "high": 152.41, "low": 146.7, "close": 150.67, "volume": 1699923 },
{ "date": new Date('2026-06-06T00:00:00.000Z'), "open": 171.46, "high": 175.69, "low": 169.74, "close": 173.59, "volume": 2886633 },
{ "date": new Date('2026-06-07T00:00:00.000Z'), "open": 183.64, "high": 188.05, "low": 182.55, "close": 186.56, "volume": 1958788 },
{ "date": new Date('2026-06-08T00:00:00.000Z'), "open": 170.64, "high": 171.98, "low": 170.03, "close": 171.4, "volume": 2591763 },
{ "date": new Date('2026-06-09T00:00:00.000Z'), "open": 152.5, "high": 155.87, "low": 152.08, "close": 154.11, "volume": 2390200 },
{ "date": new Date('2026-06-10T00:00:00.000Z'), "open": 160.09, "high": 161.14, "low": 159.72, "close": 159.98, "volume": 1215900 },
{ "date": new Date('2026-06-11T00:00:00.000Z'), "open": 182.16, "high": 184.7, "low": 178.86, "close": 179.41, "volume": 2164476 },
{ "date": new Date('2026-06-12T00:00:00.000Z'), "open": 185.21, "high": 187.86, "low": 181.4, "close": 184.07, "volume": 1974440 },
{ "date": new Date('2026-06-13T00:00:00.000Z'), "open": 165.44, "high": 167.21, "low": 163.53, "close": 164.3, "volume": 2370781 },
{ "date": new Date('2026-06-14T00:00:00.000Z'), "open": 148.68, "high": 150.88, "low": 144.98, "close": 146.88, "volume": 1514960 },
{ "date": new Date('2026-06-15T00:00:00.000Z'), "open": 156.9, "high": 158.48, "low": 154.82, "close": 157.9, "volume": 2103753 },
{ "date": new Date('2026-06-16T00:00:00.000Z'), "open": 178.83, "high": 181, "low": 177.04, "close": 179.49, "volume": 2756231 },
{ "date": new Date('2026-06-17T00:00:00.000Z'), "open": 180.61, "high": 186.25, "low": 180, "close": 183.48, "volume": 2780645 },
{ "date": new Date('2026-06-18T00:00:00.000Z'), "open": 162.75, "high": 165.54, "low": 161.08, "close": 165.12, "volume": 1689021 },
{ "date": new Date('2026-06-19T00:00:00.000Z'), "open": 152.72, "high": 156.24, "low": 151.43, "close": 153.98, "volume": 2417696 },
{ "date": new Date('2026-06-20T00:00:00.000Z'), "open": 168.5, "high": 169.63, "low": 167, "close": 167.04, "volume": 2021664 },
{ "date": new Date('2026-06-21T00:00:00.000Z'), "open": 187.13, "high": 187.91, "low": 182.74, "close": 184.39, "volume": 2177707 },
{ "date": new Date('2026-06-22T00:00:00.000Z'), "open": 180.8, "high": 184.14, "low": 179.92, "close": 183.99, "volume": 2673441 },
{ "date": new Date('2026-06-23T00:00:00.000Z'), "open": 161.89, "high": 163.1, "low": 158.54, "close": 159.99, "volume": 2589200 },
{ "date": new Date('2026-06-24T00:00:00.000Z'), "open": 151.91, "high": 155.38, "low": 149.77, "close": 153.1, "volume": 2395635 },
{ "date": new Date('2026-06-25T00:00:00.000Z'), "open": 170.7, "high": 173.49, "low": 168.15, "close": 172.64, "volume": 1714962 },
{ "date": new Date('2026-06-26T00:00:00.000Z'), "open": 190.42, "high": 192.99, "low": 187.53, "close": 188.36, "volume": 2287434 },
{ "date": new Date('2026-06-27T00:00:00.000Z'), "open": 180.11, "high": 183, "low": 179.74, "close": 182.17, "volume": 2558416 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// The same rows as a candlestick card. Indicators are computed from the close.
const candles = [
{ date: new Date('2026-08-20'), open: 243.1, high: 246.4, low: 241.8, close: 245.2, volume: 2410000 },
// …one row per period
];
```
Every indicator derives from `close`: simple and exponential averages, Bollinger bands (20 periods, two deviations), RSI with Wilder’s smoothing (14 by default), and MACD (12, 26, 9). Each needs a warm-up window, so it starts where enough rows exist rather than inventing early values. Without `open`, `high` and `low` the price draws as a line. The same helpers (`sma`, `ema`, `rsi`, `macd`, `bollinger`) are exported for your own panes.
### Hover
The crosshair runs through every pane. The headline reads the hovered close with its open, high and low; each pane’s corner reads its own value, such as RSI 54.5 or MACD with its signal, and returns to the latest reading at rest.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `data` (`Row[]`): One row per x position. Omit when using ranges.
- `x` (`key of Row`): Text, number, or Date field for the x axis.
- `close` (`key of Row`): Numeric field holding each close. Every indicator derives from it.
- `open` (`key of Row`): With high and low, draws the price as candles.
- `high` (`key of Row`): Each period’s high.
- `low` (`key of Row`): Each period’s low.
- `volume` (`key of Row`): Traded volume, for a volume pane.
- `display` (`'candle' | 'hollow' | 'ohlc' | 'line'`): How the price draws. Candles when open, high and low are set; otherwise a line.
- `overlays` (`('sma' | 'ema' | 'bollinger' | { kind, period?, deviations? })[]`): Lines over the price. Periods default to 20.
- `panes` (`('rsi' | 'macd' | 'volume' | { kind, … })[]`): Linked panes under the price, top to bottom. Defaults to RSI then MACD.
- `paneHeight` (`number`): Height of each pane in pixels. Defaults to 72.
- `scale` (`'linear' | 'log'`): Price axis scale.
- `live` (`boolean`): Follow the newest row as it arrives.
- `depth` (`boolean`): Draws price and indicator lines as lit tubes. Bands and dashed lines stay flat.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `delta` (`number`): Fractional change for the chip: 0.082 shows +8.2%.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label in the header.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the data.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): False removes the legend without changing the data. How the legend under the plot lays out: value tiles (default), a compact inline key, list rows, tinted pills, or bars that also draw each value against the largest.
- `legendSwatch` (`'square' | 'dot' | 'line'`): The mark beside each legend label. Defaults to a rounded square.
- `height` (`number`): Plot height in pixels. Defaults to 240.
- `axis` (`'minimal' | 'dots' | 'inline' | 'ruler' | 'classic' | 'segmented' | { x, y }`): Axis preset. Minimal (default) labels only the x ends and has no grid. Set one per axis with `{ x, y }`; a segmented axis can take a `gradient` to read as a range.
- `hover` (`'pills' | 'tooltip' | 'strip' | 'headline'`): The one readout for the hovered point: pills on the axes (default), a tooltip with every series, a strip docked above the plot, or the headline and tiles alone.
- `hoverStyle` (`'soft' | 'solid' | 'accent'`): How the pills or tooltip look. Soft (default) is surface glass; accent tints it with the hovered series.
- `pillPosition` (`'auto' | 'mark' | 'axis'`): Where the value pill sits: above the hovered mark, or on the y axis. Auto picks mark when there are no y labels.
- `tooltipIndicator` (`'square' | 'dot' | 'line'`): Series marker on each tooltip row, with hover="tooltip". Square by default.
- `background` (`'dots' | 'grid' | 'lines' | 'none'`): Texture behind the marks. Dots by default, with a hover spotlight.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `axisInset` (`number`): Padding between the plot edges and axis labels or pills.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `compare` (`boolean | 'headline' | 'badge'`): Drag across the plot to compare two points in time. True or headline reads the change in the headline; badge reads it in the card’s tab and leaves the headline at rest.
- `sync` (`string`): Link hover and pins with every card that uses the same name, matched by x value. A click pins them all, with a ghost pin on the others; Alt-click pins one card only.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `formatAxisValue` (`(value: number) => string`): Custom compact axis value text.
- `formatX` (`(value: string | number | Date) => string`): Custom x label text.
- `xType` (`'category' | 'number' | 'time'`): Override inferred x type. Use time for numeric Unix timestamps in milliseconds.
- `spotlight` (`boolean`): Highlight the inspected position in the plot background. Defaults to true.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
- `pillValue` (`'series' | 'stack'`): Read an individual series value (default) or its stacked height. Has no effect when the card has no stacked series.
- `decimate` (`boolean`): Defaults to true. Line and Area marks retain at most four observations per pixel column. Other marks draw every row; inspection and summaries always read the full data.
- `headline` (`number`): Override the resting headline; an active range headline takes precedence.
- `label` (`string`): Names the price series in the hover readout. Defaults to Price.
## Price chart: `PriceChartCard`
The latest price in large type, how far it moved over the period, and the path it took. Docs: https://liltui.vercel.app/finance/price
```tsx
import { PriceChartCard } from '@lilt-ui/charts/finance';
```
### Complete examples
#### Price card
```tsx
'use client';
import { PriceChartCard } from '@lilt-ui/charts/finance';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "1w", "label": "1W", "data": [
{ "date": new Date('2026-09-19T00:00:00.000Z'), "sol": 200.51, "eth": 2853.48, "btc": 56081.72 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "sol": 204.04, "eth": 2886.95, "btc": 56677.61 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "sol": 201.65, "eth": 2852.93, "btc": 57173.49 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "sol": 203.2, "eth": 2886.27, "btc": 57010.53 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "sol": 205.46, "eth": 2892.32, "btc": 57209.11 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "sol": 203.24, "eth": 2880.35, "btc": 57685.01 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "sol": 205.56, "eth": 2888.22, "btc": 58150.58 },
] },
{ "id": "1m", "label": "1M", "data": [
{ "date": new Date('2026-08-27T00:00:00.000Z'), "sol": 193.85, "eth": 2946.67, "btc": 56350.33 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "sol": 194.2, "eth": 2904.72, "btc": 56574.28 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "sol": 192.45, "eth": 2894.12, "btc": 57029.97 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "sol": 191.48, "eth": 2927.81, "btc": 56922.27 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "sol": 194.15, "eth": 2959.14, "btc": 56455.95 },
{ "date": new Date('2026-09-01T00:00:00.000Z'), "sol": 194.68, "eth": 2955.98, "btc": 56251.07 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "sol": 192.18, "eth": 2972.87, "btc": 56836.77 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "sol": 195.29, "eth": 2931.31, "btc": 56542.03 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "sol": 197.72, "eth": 2945.73, "btc": 56300.61 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "sol": 200.86, "eth": 2980.17, "btc": 55977.48 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "sol": 201.7, "eth": 2996.18, "btc": 56269.13 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "sol": 203.76, "eth": 2988.31, "btc": 55761.44 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "sol": 203.62, "eth": 2976.45, "btc": 55968.56 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "sol": 200.54, "eth": 2966.15, "btc": 56198.91 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "sol": 199.31, "eth": 2950.26, "btc": 56159.55 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "sol": 197.94, "eth": 2916.28, "btc": 56718.02 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "sol": 195.54, "eth": 2915.04, "btc": 56132.61 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "sol": 196.79, "eth": 2890.51, "btc": 56047.74 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "sol": 197.52, "eth": 2858.61, "btc": 56454.51 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "sol": 200.66, "eth": 2871.09, "btc": 56180.75 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "sol": 203.59, "eth": 2868.24, "btc": 56471.08 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "sol": 205.27, "eth": 2867.31, "btc": 56097.68 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "sol": 203.49, "eth": 2875.51, "btc": 55673.1 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "sol": 200.51, "eth": 2853.48, "btc": 56081.72 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "sol": 204.04, "eth": 2886.95, "btc": 56677.61 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "sol": 201.65, "eth": 2852.93, "btc": 57173.49 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "sol": 203.2, "eth": 2886.27, "btc": 57010.53 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "sol": 205.46, "eth": 2892.32, "btc": 57209.11 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "sol": 203.24, "eth": 2880.35, "btc": 57685.01 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "sol": 205.56, "eth": 2888.22, "btc": 58150.58 },
] },
{ "id": "3m", "label": "3M", "data": [
{ "date": new Date('2026-06-28T00:00:00.000Z'), "sol": 178.33, "eth": 3114.78, "btc": 58055.61 },
{ "date": new Date('2026-06-29T00:00:00.000Z'), "sol": 176.69, "eth": 3105.79, "btc": 57705.17 },
{ "date": new Date('2026-06-30T00:00:00.000Z'), "sol": 176.71, "eth": 3133.73, "btc": 57917.31 },
{ "date": new Date('2026-07-01T00:00:00.000Z'), "sol": 175.69, "eth": 3139.42, "btc": 57600.25 },
{ "date": new Date('2026-07-02T00:00:00.000Z'), "sol": 175.31, "eth": 3158.46, "btc": 58221.38 },
{ "date": new Date('2026-07-03T00:00:00.000Z'), "sol": 178.41, "eth": 3193.35, "btc": 57757.69 },
{ "date": new Date('2026-07-04T00:00:00.000Z'), "sol": 179.67, "eth": 3236.06, "btc": 57547.68 },
{ "date": new Date('2026-07-05T00:00:00.000Z'), "sol": 178.41, "eth": 3203.25, "btc": 57552.38 },
{ "date": new Date('2026-07-06T00:00:00.000Z'), "sol": 181.04, "eth": 3180.85, "btc": 57412.97 },
{ "date": new Date('2026-07-07T00:00:00.000Z'), "sol": 178.74, "eth": 3210.26, "btc": 57974.23 },
{ "date": new Date('2026-07-08T00:00:00.000Z'), "sol": 180.24, "eth": 3198.07, "btc": 58263.99 },
{ "date": new Date('2026-07-09T00:00:00.000Z'), "sol": 178.88, "eth": 3149.91, "btc": 57941.99 },
{ "date": new Date('2026-07-10T00:00:00.000Z'), "sol": 180.16, "eth": 3185.55, "btc": 58606.63 },
{ "date": new Date('2026-07-11T00:00:00.000Z'), "sol": 178.34, "eth": 3188.25, "btc": 58399.33 },
{ "date": new Date('2026-07-12T00:00:00.000Z'), "sol": 181.53, "eth": 3208.83, "btc": 58807.43 },
{ "date": new Date('2026-07-13T00:00:00.000Z'), "sol": 180.7, "eth": 3236.75, "btc": 58793.49 },
{ "date": new Date('2026-07-14T00:00:00.000Z'), "sol": 181.02, "eth": 3276.68, "btc": 58336.69 },
{ "date": new Date('2026-07-15T00:00:00.000Z'), "sol": 182.81, "eth": 3248.57, "btc": 58167.96 },
{ "date": new Date('2026-07-16T00:00:00.000Z'), "sol": 185.86, "eth": 3209.49, "btc": 58155.55 },
{ "date": new Date('2026-07-17T00:00:00.000Z'), "sol": 184.07, "eth": 3211.69, "btc": 57973.01 },
{ "date": new Date('2026-07-18T00:00:00.000Z'), "sol": 182.15, "eth": 3208.88, "btc": 57863.56 },
{ "date": new Date('2026-07-19T00:00:00.000Z'), "sol": 182.95, "eth": 3204.42, "btc": 57279.63 },
{ "date": new Date('2026-07-20T00:00:00.000Z'), "sol": 180.08, "eth": 3172.81, "btc": 56944.52 },
{ "date": new Date('2026-07-21T00:00:00.000Z'), "sol": 182.21, "eth": 3167.33, "btc": 57572.83 },
{ "date": new Date('2026-07-22T00:00:00.000Z'), "sol": 182.59, "eth": 3149.79, "btc": 57300.87 },
{ "date": new Date('2026-07-23T00:00:00.000Z'), "sol": 180, "eth": 3104.19, "btc": 57376.64 },
{ "date": new Date('2026-07-24T00:00:00.000Z'), "sol": 181.3, "eth": 3094.34, "btc": 57719.59 },
{ "date": new Date('2026-07-25T00:00:00.000Z'), "sol": 179.41, "eth": 3092.14, "btc": 57606.64 },
{ "date": new Date('2026-07-26T00:00:00.000Z'), "sol": 179.78, "eth": 3131.94, "btc": 57593.46 },
{ "date": new Date('2026-07-27T00:00:00.000Z'), "sol": 182.53, "eth": 3171.29, "btc": 57019.68 },
{ "date": new Date('2026-07-28T00:00:00.000Z'), "sol": 185.06, "eth": 3142.02, "btc": 56688.54 },
{ "date": new Date('2026-07-29T00:00:00.000Z'), "sol": 182.69, "eth": 3131.78, "btc": 56402.39 },
{ "date": new Date('2026-07-30T00:00:00.000Z'), "sol": 180.14, "eth": 3088.76, "btc": 55907.28 },
{ "date": new Date('2026-07-31T00:00:00.000Z'), "sol": 179.29, "eth": 3061.81, "btc": 55449.44 },
{ "date": new Date('2026-08-01T00:00:00.000Z'), "sol": 181.63, "eth": 3015.76, "btc": 54900.37 },
{ "date": new Date('2026-08-02T00:00:00.000Z'), "sol": 182.99, "eth": 3022.88, "btc": 54690.3 },
{ "date": new Date('2026-08-03T00:00:00.000Z'), "sol": 181.94, "eth": 3013.52, "btc": 55236.43 },
{ "date": new Date('2026-08-04T00:00:00.000Z'), "sol": 182.87, "eth": 2981.17, "btc": 55321.6 },
{ "date": new Date('2026-08-05T00:00:00.000Z'), "sol": 180.65, "eth": 3000.4, "btc": 55704.81 },
{ "date": new Date('2026-08-06T00:00:00.000Z'), "sol": 183.38, "eth": 2999.36, "btc": 55388.37 },
{ "date": new Date('2026-08-07T00:00:00.000Z'), "sol": 181.35, "eth": 3011.62, "btc": 55447.87 },
{ "date": new Date('2026-08-08T00:00:00.000Z'), "sol": 181.68, "eth": 2990.25, "btc": 54880.08 },
{ "date": new Date('2026-08-09T00:00:00.000Z'), "sol": 184.09, "eth": 3016.12, "btc": 54574.38 },
{ "date": new Date('2026-08-10T00:00:00.000Z'), "sol": 184.76, "eth": 3044.61, "btc": 54863.24 },
{ "date": new Date('2026-08-11T00:00:00.000Z'), "sol": 184.06, "eth": 3016.25, "btc": 55317.46 },
{ "date": new Date('2026-08-12T00:00:00.000Z'), "sol": 182.38, "eth": 3005.12, "btc": 55893.55 },
{ "date": new Date('2026-08-13T00:00:00.000Z'), "sol": 183.66, "eth": 3018.77, "btc": 55783.45 },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "sol": 181.67, "eth": 3016.1, "btc": 56083.1 },
{ "date": new Date('2026-08-15T00:00:00.000Z'), "sol": 184.46, "eth": 3035.05, "btc": 56148.98 },
{ "date": new Date('2026-08-16T00:00:00.000Z'), "sol": 186.13, "eth": 3027.01, "btc": 56030.42 },
{ "date": new Date('2026-08-17T00:00:00.000Z'), "sol": 184.01, "eth": 3012.7, "btc": 55646.03 },
{ "date": new Date('2026-08-18T00:00:00.000Z'), "sol": 185.05, "eth": 2990.08, "btc": 56204.68 },
{ "date": new Date('2026-08-19T00:00:00.000Z'), "sol": 183.2, "eth": 3000.22, "btc": 56350.26 },
{ "date": new Date('2026-08-20T00:00:00.000Z'), "sol": 182.24, "eth": 2970.7, "btc": 56407.69 },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "sol": 184.51, "eth": 3012.86, "btc": 57050.76 },
{ "date": new Date('2026-08-22T00:00:00.000Z'), "sol": 186.44, "eth": 2967.77, "btc": 57543.41 },
{ "date": new Date('2026-08-23T00:00:00.000Z'), "sol": 188.9, "eth": 3006.18, "btc": 57098.29 },
{ "date": new Date('2026-08-24T00:00:00.000Z'), "sol": 191.85, "eth": 3031, "btc": 56564.59 },
{ "date": new Date('2026-08-25T00:00:00.000Z'), "sol": 190.53, "eth": 2987.88, "btc": 56329.36 },
{ "date": new Date('2026-08-26T00:00:00.000Z'), "sol": 190.78, "eth": 2942.4, "btc": 56339.99 },
{ "date": new Date('2026-08-27T00:00:00.000Z'), "sol": 193.85, "eth": 2946.67, "btc": 56350.33 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "sol": 194.2, "eth": 2904.72, "btc": 56574.28 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "sol": 192.45, "eth": 2894.12, "btc": 57029.97 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "sol": 191.48, "eth": 2927.81, "btc": 56922.27 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "sol": 194.15, "eth": 2959.14, "btc": 56455.95 },
{ "date": new Date('2026-09-01T00:00:00.000Z'), "sol": 194.68, "eth": 2955.98, "btc": 56251.07 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "sol": 192.18, "eth": 2972.87, "btc": 56836.77 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "sol": 195.29, "eth": 2931.31, "btc": 56542.03 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "sol": 197.72, "eth": 2945.73, "btc": 56300.61 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "sol": 200.86, "eth": 2980.17, "btc": 55977.48 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "sol": 201.7, "eth": 2996.18, "btc": 56269.13 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "sol": 203.76, "eth": 2988.31, "btc": 55761.44 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "sol": 203.62, "eth": 2976.45, "btc": 55968.56 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "sol": 200.54, "eth": 2966.15, "btc": 56198.91 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "sol": 199.31, "eth": 2950.26, "btc": 56159.55 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "sol": 197.94, "eth": 2916.28, "btc": 56718.02 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "sol": 195.54, "eth": 2915.04, "btc": 56132.61 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "sol": 196.79, "eth": 2890.51, "btc": 56047.74 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "sol": 197.52, "eth": 2858.61, "btc": 56454.51 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "sol": 200.66, "eth": 2871.09, "btc": 56180.75 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "sol": 203.59, "eth": 2868.24, "btc": 56471.08 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "sol": 205.27, "eth": 2867.31, "btc": 56097.68 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "sol": 203.49, "eth": 2875.51, "btc": 55673.1 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "sol": 200.51, "eth": 2853.48, "btc": 56081.72 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "sol": 204.04, "eth": 2886.95, "btc": 56677.61 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "sol": 201.65, "eth": 2852.93, "btc": 57173.49 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "sol": 203.2, "eth": 2886.27, "btc": 57010.53 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "sol": 205.46, "eth": 2892.32, "btc": 57209.11 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "sol": 203.24, "eth": 2880.35, "btc": 57685.01 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "sol": 205.56, "eth": 2888.22, "btc": 58150.58 },
] },
];
export function Example() {
return (
);
}
```
#### Compared
Three tokens rebased to their change over the quarter, on one axis.
```tsx
'use client';
import { PriceChartCard } from '@lilt-ui/charts/finance';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "current", "label": "This period", "data": [
{ "date": new Date('2026-06-28T00:00:00.000Z'), "sol": 178.33, "eth": 3114.78, "btc": 58055.61 },
{ "date": new Date('2026-06-29T00:00:00.000Z'), "sol": 176.69, "eth": 3105.79, "btc": 57705.17 },
{ "date": new Date('2026-06-30T00:00:00.000Z'), "sol": 176.71, "eth": 3133.73, "btc": 57917.31 },
{ "date": new Date('2026-07-01T00:00:00.000Z'), "sol": 175.69, "eth": 3139.42, "btc": 57600.25 },
{ "date": new Date('2026-07-02T00:00:00.000Z'), "sol": 175.31, "eth": 3158.46, "btc": 58221.38 },
{ "date": new Date('2026-07-03T00:00:00.000Z'), "sol": 178.41, "eth": 3193.35, "btc": 57757.69 },
{ "date": new Date('2026-07-04T00:00:00.000Z'), "sol": 179.67, "eth": 3236.06, "btc": 57547.68 },
{ "date": new Date('2026-07-05T00:00:00.000Z'), "sol": 178.41, "eth": 3203.25, "btc": 57552.38 },
{ "date": new Date('2026-07-06T00:00:00.000Z'), "sol": 181.04, "eth": 3180.85, "btc": 57412.97 },
{ "date": new Date('2026-07-07T00:00:00.000Z'), "sol": 178.74, "eth": 3210.26, "btc": 57974.23 },
{ "date": new Date('2026-07-08T00:00:00.000Z'), "sol": 180.24, "eth": 3198.07, "btc": 58263.99 },
{ "date": new Date('2026-07-09T00:00:00.000Z'), "sol": 178.88, "eth": 3149.91, "btc": 57941.99 },
{ "date": new Date('2026-07-10T00:00:00.000Z'), "sol": 180.16, "eth": 3185.55, "btc": 58606.63 },
{ "date": new Date('2026-07-11T00:00:00.000Z'), "sol": 178.34, "eth": 3188.25, "btc": 58399.33 },
{ "date": new Date('2026-07-12T00:00:00.000Z'), "sol": 181.53, "eth": 3208.83, "btc": 58807.43 },
{ "date": new Date('2026-07-13T00:00:00.000Z'), "sol": 180.7, "eth": 3236.75, "btc": 58793.49 },
{ "date": new Date('2026-07-14T00:00:00.000Z'), "sol": 181.02, "eth": 3276.68, "btc": 58336.69 },
{ "date": new Date('2026-07-15T00:00:00.000Z'), "sol": 182.81, "eth": 3248.57, "btc": 58167.96 },
{ "date": new Date('2026-07-16T00:00:00.000Z'), "sol": 185.86, "eth": 3209.49, "btc": 58155.55 },
{ "date": new Date('2026-07-17T00:00:00.000Z'), "sol": 184.07, "eth": 3211.69, "btc": 57973.01 },
{ "date": new Date('2026-07-18T00:00:00.000Z'), "sol": 182.15, "eth": 3208.88, "btc": 57863.56 },
{ "date": new Date('2026-07-19T00:00:00.000Z'), "sol": 182.95, "eth": 3204.42, "btc": 57279.63 },
{ "date": new Date('2026-07-20T00:00:00.000Z'), "sol": 180.08, "eth": 3172.81, "btc": 56944.52 },
{ "date": new Date('2026-07-21T00:00:00.000Z'), "sol": 182.21, "eth": 3167.33, "btc": 57572.83 },
{ "date": new Date('2026-07-22T00:00:00.000Z'), "sol": 182.59, "eth": 3149.79, "btc": 57300.87 },
{ "date": new Date('2026-07-23T00:00:00.000Z'), "sol": 180, "eth": 3104.19, "btc": 57376.64 },
{ "date": new Date('2026-07-24T00:00:00.000Z'), "sol": 181.3, "eth": 3094.34, "btc": 57719.59 },
{ "date": new Date('2026-07-25T00:00:00.000Z'), "sol": 179.41, "eth": 3092.14, "btc": 57606.64 },
{ "date": new Date('2026-07-26T00:00:00.000Z'), "sol": 179.78, "eth": 3131.94, "btc": 57593.46 },
{ "date": new Date('2026-07-27T00:00:00.000Z'), "sol": 182.53, "eth": 3171.29, "btc": 57019.68 },
{ "date": new Date('2026-07-28T00:00:00.000Z'), "sol": 185.06, "eth": 3142.02, "btc": 56688.54 },
{ "date": new Date('2026-07-29T00:00:00.000Z'), "sol": 182.69, "eth": 3131.78, "btc": 56402.39 },
{ "date": new Date('2026-07-30T00:00:00.000Z'), "sol": 180.14, "eth": 3088.76, "btc": 55907.28 },
{ "date": new Date('2026-07-31T00:00:00.000Z'), "sol": 179.29, "eth": 3061.81, "btc": 55449.44 },
{ "date": new Date('2026-08-01T00:00:00.000Z'), "sol": 181.63, "eth": 3015.76, "btc": 54900.37 },
{ "date": new Date('2026-08-02T00:00:00.000Z'), "sol": 182.99, "eth": 3022.88, "btc": 54690.3 },
{ "date": new Date('2026-08-03T00:00:00.000Z'), "sol": 181.94, "eth": 3013.52, "btc": 55236.43 },
{ "date": new Date('2026-08-04T00:00:00.000Z'), "sol": 182.87, "eth": 2981.17, "btc": 55321.6 },
{ "date": new Date('2026-08-05T00:00:00.000Z'), "sol": 180.65, "eth": 3000.4, "btc": 55704.81 },
{ "date": new Date('2026-08-06T00:00:00.000Z'), "sol": 183.38, "eth": 2999.36, "btc": 55388.37 },
{ "date": new Date('2026-08-07T00:00:00.000Z'), "sol": 181.35, "eth": 3011.62, "btc": 55447.87 },
{ "date": new Date('2026-08-08T00:00:00.000Z'), "sol": 181.68, "eth": 2990.25, "btc": 54880.08 },
{ "date": new Date('2026-08-09T00:00:00.000Z'), "sol": 184.09, "eth": 3016.12, "btc": 54574.38 },
{ "date": new Date('2026-08-10T00:00:00.000Z'), "sol": 184.76, "eth": 3044.61, "btc": 54863.24 },
{ "date": new Date('2026-08-11T00:00:00.000Z'), "sol": 184.06, "eth": 3016.25, "btc": 55317.46 },
{ "date": new Date('2026-08-12T00:00:00.000Z'), "sol": 182.38, "eth": 3005.12, "btc": 55893.55 },
{ "date": new Date('2026-08-13T00:00:00.000Z'), "sol": 183.66, "eth": 3018.77, "btc": 55783.45 },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "sol": 181.67, "eth": 3016.1, "btc": 56083.1 },
{ "date": new Date('2026-08-15T00:00:00.000Z'), "sol": 184.46, "eth": 3035.05, "btc": 56148.98 },
{ "date": new Date('2026-08-16T00:00:00.000Z'), "sol": 186.13, "eth": 3027.01, "btc": 56030.42 },
{ "date": new Date('2026-08-17T00:00:00.000Z'), "sol": 184.01, "eth": 3012.7, "btc": 55646.03 },
{ "date": new Date('2026-08-18T00:00:00.000Z'), "sol": 185.05, "eth": 2990.08, "btc": 56204.68 },
{ "date": new Date('2026-08-19T00:00:00.000Z'), "sol": 183.2, "eth": 3000.22, "btc": 56350.26 },
{ "date": new Date('2026-08-20T00:00:00.000Z'), "sol": 182.24, "eth": 2970.7, "btc": 56407.69 },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "sol": 184.51, "eth": 3012.86, "btc": 57050.76 },
{ "date": new Date('2026-08-22T00:00:00.000Z'), "sol": 186.44, "eth": 2967.77, "btc": 57543.41 },
{ "date": new Date('2026-08-23T00:00:00.000Z'), "sol": 188.9, "eth": 3006.18, "btc": 57098.29 },
{ "date": new Date('2026-08-24T00:00:00.000Z'), "sol": 191.85, "eth": 3031, "btc": 56564.59 },
{ "date": new Date('2026-08-25T00:00:00.000Z'), "sol": 190.53, "eth": 2987.88, "btc": 56329.36 },
{ "date": new Date('2026-08-26T00:00:00.000Z'), "sol": 190.78, "eth": 2942.4, "btc": 56339.99 },
{ "date": new Date('2026-08-27T00:00:00.000Z'), "sol": 193.85, "eth": 2946.67, "btc": 56350.33 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "sol": 194.2, "eth": 2904.72, "btc": 56574.28 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "sol": 192.45, "eth": 2894.12, "btc": 57029.97 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "sol": 191.48, "eth": 2927.81, "btc": 56922.27 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "sol": 194.15, "eth": 2959.14, "btc": 56455.95 },
{ "date": new Date('2026-09-01T00:00:00.000Z'), "sol": 194.68, "eth": 2955.98, "btc": 56251.07 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "sol": 192.18, "eth": 2972.87, "btc": 56836.77 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "sol": 195.29, "eth": 2931.31, "btc": 56542.03 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "sol": 197.72, "eth": 2945.73, "btc": 56300.61 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "sol": 200.86, "eth": 2980.17, "btc": 55977.48 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "sol": 201.7, "eth": 2996.18, "btc": 56269.13 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "sol": 203.76, "eth": 2988.31, "btc": 55761.44 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "sol": 203.62, "eth": 2976.45, "btc": 55968.56 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "sol": 200.54, "eth": 2966.15, "btc": 56198.91 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "sol": 199.31, "eth": 2950.26, "btc": 56159.55 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "sol": 197.94, "eth": 2916.28, "btc": 56718.02 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "sol": 195.54, "eth": 2915.04, "btc": 56132.61 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "sol": 196.79, "eth": 2890.51, "btc": 56047.74 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "sol": 197.52, "eth": 2858.61, "btc": 56454.51 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "sol": 200.66, "eth": 2871.09, "btc": 56180.75 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "sol": 203.59, "eth": 2868.24, "btc": 56471.08 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "sol": 205.27, "eth": 2867.31, "btc": 56097.68 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "sol": 203.49, "eth": 2875.51, "btc": 55673.1 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "sol": 200.51, "eth": 2853.48, "btc": 56081.72 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "sol": 204.04, "eth": 2886.95, "btc": 56677.61 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "sol": 201.65, "eth": 2852.93, "btc": 57173.49 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "sol": 203.2, "eth": 2886.27, "btc": 57010.53 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "sol": 205.46, "eth": 2892.32, "btc": 57209.11 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "sol": 203.24, "eth": 2880.35, "btc": 57685.01 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "sol": 205.56, "eth": 2888.22, "btc": 58150.58 },
] },
{ "id": "previous", "label": "Last period", "data": [
{ "date": new Date('2026-03-30T00:00:00.000Z'), "sol": 149.8, "eth": 2616.42, "btc": 48766.71 },
{ "date": new Date('2026-03-31T00:00:00.000Z'), "sol": 163.74, "eth": 2878.2, "btc": 53476.55 },
{ "date": new Date('2026-04-01T00:00:00.000Z'), "sol": 156.63, "eth": 2777.72, "btc": 51337.62 },
{ "date": new Date('2026-04-02T00:00:00.000Z'), "sol": 136.7, "eth": 2442.79, "btc": 44818.81 },
{ "date": new Date('2026-04-03T00:00:00.000Z'), "sol": 133.32, "eth": 2401.97, "btc": 44276.72 },
{ "date": new Date('2026-04-04T00:00:00.000Z'), "sol": 153.32, "eth": 2744.24, "btc": 49634.69 },
{ "date": new Date('2026-04-05T00:00:00.000Z'), "sol": 167.07, "eth": 3009.11, "btc": 53511.8 },
{ "date": new Date('2026-04-06T00:00:00.000Z'), "sol": 154.99, "eth": 2782.72, "btc": 49996.84 },
{ "date": new Date('2026-04-07T00:00:00.000Z'), "sol": 138.59, "eth": 2434.93, "btc": 43949.38 },
{ "date": new Date('2026-04-08T00:00:00.000Z'), "sol": 137.88, "eth": 2476.46, "btc": 44722.57 },
{ "date": new Date('2026-04-09T00:00:00.000Z'), "sol": 158.22, "eth": 2807.31, "btc": 51145.01 },
{ "date": new Date('2026-04-10T00:00:00.000Z'), "sol": 166.15, "eth": 2925.67, "btc": 53817.07 },
{ "date": new Date('2026-04-11T00:00:00.000Z'), "sol": 153.08, "eth": 2706.75, "btc": 49797.93 },
{ "date": new Date('2026-04-12T00:00:00.000Z'), "sol": 134.89, "eth": 2411.52, "btc": 44172.02 },
{ "date": new Date('2026-04-13T00:00:00.000Z'), "sol": 142.6, "eth": 2520.74, "btc": 46197.06 },
{ "date": new Date('2026-04-14T00:00:00.000Z'), "sol": 161.6, "eth": 2895.27, "btc": 52590.69 },
{ "date": new Date('2026-04-15T00:00:00.000Z'), "sol": 167.19, "eth": 3026.31, "btc": 53879.28 },
{ "date": new Date('2026-04-16T00:00:00.000Z'), "sol": 151.77, "eth": 2697.04, "btc": 48292.36 },
{ "date": new Date('2026-04-17T00:00:00.000Z'), "sol": 139.61, "eth": 2410.9, "btc": 43685.15 },
{ "date": new Date('2026-04-18T00:00:00.000Z'), "sol": 147.67, "eth": 2576.6, "btc": 46509.28 },
{ "date": new Date('2026-04-19T00:00:00.000Z'), "sol": 165.51, "eth": 2915.69, "btc": 52576.58 },
{ "date": new Date('2026-04-20T00:00:00.000Z'), "sol": 167.3, "eth": 2930.31, "btc": 52379.9 },
{ "date": new Date('2026-04-21T00:00:00.000Z'), "sol": 146.08, "eth": 2573.8, "btc": 46193.7 },
{ "date": new Date('2026-04-22T00:00:00.000Z'), "sol": 136.68, "eth": 2375.93, "btc": 43187.42 },
{ "date": new Date('2026-04-23T00:00:00.000Z'), "sol": 149.85, "eth": 2585.09, "btc": 47027.81 },
{ "date": new Date('2026-04-24T00:00:00.000Z'), "sol": 166, "eth": 2854.45, "btc": 52760.59 },
{ "date": new Date('2026-04-25T00:00:00.000Z'), "sol": 163.5, "eth": 2790.6, "btc": 52053.89 },
{ "date": new Date('2026-04-26T00:00:00.000Z'), "sol": 142.37, "eth": 2453.73, "btc": 45712.97 },
{ "date": new Date('2026-04-27T00:00:00.000Z'), "sol": 135.43, "eth": 2359.29, "btc": 43385.22 },
{ "date": new Date('2026-04-28T00:00:00.000Z'), "sol": 153.34, "eth": 2664.14, "btc": 47901.09 },
{ "date": new Date('2026-04-29T00:00:00.000Z'), "sol": 171.5, "eth": 2911.84, "btc": 52535.63 },
{ "date": new Date('2026-04-30T00:00:00.000Z'), "sol": 161.92, "eth": 2775.78, "btc": 49990.94 },
{ "date": new Date('2026-05-01T00:00:00.000Z'), "sol": 140.16, "eth": 2403.19, "btc": 43498.27 },
{ "date": new Date('2026-05-02T00:00:00.000Z'), "sol": 136.35, "eth": 2328.59, "btc": 42170.77 },
{ "date": new Date('2026-05-03T00:00:00.000Z'), "sol": 156.1, "eth": 2591.86, "btc": 47183.51 },
{ "date": new Date('2026-05-04T00:00:00.000Z'), "sol": 170.16, "eth": 2810.9, "btc": 50855 },
{ "date": new Date('2026-05-05T00:00:00.000Z'), "sol": 158.04, "eth": 2617.67, "btc": 47980.74 },
{ "date": new Date('2026-05-06T00:00:00.000Z'), "sol": 139.98, "eth": 2281.94, "btc": 42346 },
{ "date": new Date('2026-05-07T00:00:00.000Z'), "sol": 139.37, "eth": 2314.7, "btc": 42974.77 },
{ "date": new Date('2026-05-08T00:00:00.000Z'), "sol": 160.99, "eth": 2633.1, "btc": 48624.76 },
{ "date": new Date('2026-05-09T00:00:00.000Z'), "sol": 168.44, "eth": 2797.18, "btc": 51499.79 },
{ "date": new Date('2026-05-10T00:00:00.000Z'), "sol": 154.36, "eth": 2540.57, "btc": 46627.12 },
{ "date": new Date('2026-05-11T00:00:00.000Z'), "sol": 139.24, "eth": 2281.24, "btc": 41277.29 },
{ "date": new Date('2026-05-12T00:00:00.000Z'), "sol": 145.15, "eth": 2391.93, "btc": 43102.14 },
{ "date": new Date('2026-05-13T00:00:00.000Z'), "sol": 164.65, "eth": 2698.22, "btc": 49484.91 },
{ "date": new Date('2026-05-14T00:00:00.000Z'), "sol": 168.44, "eth": 2775.41, "btc": 51621.15 },
{ "date": new Date('2026-05-15T00:00:00.000Z'), "sol": 152.46, "eth": 2506.01, "btc": 46308.25 },
{ "date": new Date('2026-05-16T00:00:00.000Z'), "sol": 136.46, "eth": 2265.6, "btc": 42127.6 },
{ "date": new Date('2026-05-17T00:00:00.000Z'), "sol": 148, "eth": 2435.11, "btc": 45050.02 },
{ "date": new Date('2026-05-18T00:00:00.000Z'), "sol": 169.13, "eth": 2750.59, "btc": 50913.83 },
{ "date": new Date('2026-05-19T00:00:00.000Z'), "sol": 168.26, "eth": 2754.9, "btc": 50883.54 },
{ "date": new Date('2026-05-20T00:00:00.000Z'), "sol": 150.1, "eth": 2425.34, "btc": 45589.28 },
{ "date": new Date('2026-05-21T00:00:00.000Z'), "sol": 137.4, "eth": 2250.58, "btc": 42270.58 },
{ "date": new Date('2026-05-22T00:00:00.000Z'), "sol": 149.58, "eth": 2438.3, "btc": 46299.17 },
{ "date": new Date('2026-05-23T00:00:00.000Z'), "sol": 169.67, "eth": 2770.58, "btc": 52463.06 },
{ "date": new Date('2026-05-24T00:00:00.000Z'), "sol": 168.13, "eth": 2676.28, "btc": 51891.66 },
{ "date": new Date('2026-05-25T00:00:00.000Z'), "sol": 149.9, "eth": 2385.31, "btc": 45305.66 },
{ "date": new Date('2026-05-26T00:00:00.000Z'), "sol": 144.52, "eth": 2283, "btc": 42611.39 },
{ "date": new Date('2026-05-27T00:00:00.000Z'), "sol": 160.08, "eth": 2510.3, "btc": 47325.67 },
{ "date": new Date('2026-05-28T00:00:00.000Z'), "sol": 176.81, "eth": 2726.9, "btc": 52213.81 },
{ "date": new Date('2026-05-29T00:00:00.000Z'), "sol": 171.8, "eth": 2611.51, "btc": 49940.93 },
{ "date": new Date('2026-05-30T00:00:00.000Z'), "sol": 151.1, "eth": 2259.83, "btc": 44013.95 },
{ "date": new Date('2026-05-31T00:00:00.000Z'), "sol": 146.37, "eth": 2201.16, "btc": 43374.95 },
{ "date": new Date('2026-06-01T00:00:00.000Z'), "sol": 164.58, "eth": 2516.5, "btc": 48925.65 },
{ "date": new Date('2026-06-02T00:00:00.000Z'), "sol": 180.54, "eth": 2751.64, "btc": 52497.11 },
{ "date": new Date('2026-06-03T00:00:00.000Z'), "sol": 169.09, "eth": 2567.47, "btc": 48857.84 },
{ "date": new Date('2026-06-04T00:00:00.000Z'), "sol": 147.1, "eth": 2275.45, "btc": 43503.21 },
{ "date": new Date('2026-06-05T00:00:00.000Z'), "sol": 150.67, "eth": 2261.58, "btc": 43623.6 },
{ "date": new Date('2026-06-06T00:00:00.000Z'), "sol": 173.59, "eth": 2586.23, "btc": 49429.69 },
{ "date": new Date('2026-06-07T00:00:00.000Z'), "sol": 186.56, "eth": 2767.93, "btc": 51990.96 },
{ "date": new Date('2026-06-08T00:00:00.000Z'), "sol": 171.4, "eth": 2545.37, "btc": 47802.81 },
{ "date": new Date('2026-06-09T00:00:00.000Z'), "sol": 154.11, "eth": 2260.12, "btc": 42173.48 },
{ "date": new Date('2026-06-10T00:00:00.000Z'), "sol": 159.98, "eth": 2338.57, "btc": 43974.07 },
{ "date": new Date('2026-06-11T00:00:00.000Z'), "sol": 179.41, "eth": 2653.59, "btc": 50276.99 },
{ "date": new Date('2026-06-12T00:00:00.000Z'), "sol": 184.07, "eth": 2724.66, "btc": 51865.15 },
{ "date": new Date('2026-06-13T00:00:00.000Z'), "sol": 164.3, "eth": 2420.7, "btc": 47079.58 },
{ "date": new Date('2026-06-14T00:00:00.000Z'), "sol": 146.88, "eth": 2189.64, "btc": 42164.12 },
{ "date": new Date('2026-06-15T00:00:00.000Z'), "sol": 157.9, "eth": 2319.35, "btc": 44972.86 },
{ "date": new Date('2026-06-16T00:00:00.000Z'), "sol": 179.49, "eth": 2597.71, "btc": 51302.11 },
{ "date": new Date('2026-06-17T00:00:00.000Z'), "sol": 183.48, "eth": 2625.24, "btc": 51369.97 },
{ "date": new Date('2026-06-18T00:00:00.000Z'), "sol": 165.12, "eth": 2326.3, "btc": 45801.09 },
{ "date": new Date('2026-06-19T00:00:00.000Z'), "sol": 153.98, "eth": 2150.9, "btc": 42081.36 },
{ "date": new Date('2026-06-20T00:00:00.000Z'), "sol": 167.04, "eth": 2360.43, "btc": 45700.6 },
{ "date": new Date('2026-06-21T00:00:00.000Z'), "sol": 184.39, "eth": 2624.13, "btc": 51574.04 },
{ "date": new Date('2026-06-22T00:00:00.000Z'), "sol": 183.99, "eth": 2603.23, "btc": 51107.6 },
{ "date": new Date('2026-06-23T00:00:00.000Z'), "sol": 159.99, "eth": 2263.51, "btc": 45361.42 },
{ "date": new Date('2026-06-24T00:00:00.000Z'), "sol": 153.1, "eth": 2174.35, "btc": 42948.55 },
{ "date": new Date('2026-06-25T00:00:00.000Z'), "sol": 172.64, "eth": 2430.24, "btc": 48069.37 },
{ "date": new Date('2026-06-26T00:00:00.000Z'), "sol": 188.36, "eth": 2669.46, "btc": 53461.55 },
{ "date": new Date('2026-06-27T00:00:00.000Z'), "sol": 182.17, "eth": 2559.51, "btc": 51532.43 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per day with a price field; other fields can hold other instruments.
const prices = [
{ date: new Date('2026-06-28'), sol: 178.33, eth: 3114.78 },
// …one row per day
];
```
The headline is the latest price and the chip the change over the period, with the change in money beside it. The area is green when the period rose and red when it fell. With `versus`, every instrument is rebased to its change since the first row, so a $250 token and a $3,000 token share one axis.
### Hover
Hover a day to move the headline to its price. With `versus`, the tiles read each instrument’s change at that day and the pill follows the line nearest the pointer.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `data` (`Row[]`): One row per x position. Omit when using ranges.
- `x` (`key of Row`): Text, number, or Date field for the x axis.
- `price` (`key of Row`): Numeric field holding the price or level.
- `symbol` (`string`): Ticker in the heading, such as SOL.
- `name` (`string`): Full name beside the ticker.
- `icon` (`ReactNode`): A logo or glyph before the ticker.
- `display` (`'area' | 'line'`): Area (default) or line.
- `versus` (`{ key, label?, color? }[]`): Other instruments to compare, all rebased to percent change.
- `depth` (`boolean`): Draws the price line as a lit tube with a soft shadow.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `delta` (`number`): Fractional change for the chip: 0.082 shows +8.2%.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label in the header.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the data.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): False removes the legend without changing the data. How the legend under the plot lays out: value tiles (default), a compact inline key, list rows, tinted pills, or bars that also draw each value against the largest.
- `legendSwatch` (`'square' | 'dot' | 'line'`): The mark beside each legend label. Defaults to a rounded square.
- `height` (`number`): Plot height in pixels. Defaults to 240.
- `axis` (`'minimal' | 'dots' | 'inline' | 'ruler' | 'classic' | 'segmented' | { x, y }`): Axis preset. Minimal (default) labels only the x ends and has no grid. Set one per axis with `{ x, y }`; a segmented axis can take a `gradient` to read as a range.
- `hover` (`'pills' | 'tooltip' | 'strip' | 'headline'`): The one readout for the hovered point: pills on the axes (default), a tooltip with every series, a strip docked above the plot, or the headline and tiles alone.
- `hoverStyle` (`'soft' | 'solid' | 'accent'`): How the pills or tooltip look. Soft (default) is surface glass; accent tints it with the hovered series.
- `pillPosition` (`'auto' | 'mark' | 'axis'`): Where the value pill sits: above the hovered mark, or on the y axis. Auto picks mark when there are no y labels.
- `tooltipIndicator` (`'square' | 'dot' | 'line'`): Series marker on each tooltip row, with hover="tooltip". Square by default.
- `background` (`'dots' | 'grid' | 'lines' | 'none'`): Texture behind the marks. Dots by default, with a hover spotlight.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `axisInset` (`number`): Padding between the plot edges and axis labels or pills.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `compare` (`boolean | 'headline' | 'badge'`): Drag across the plot to compare two points in time. True or headline reads the change in the headline; badge reads it in the card’s tab and leaves the headline at rest.
- `sync` (`string`): Link hover and pins with every card that uses the same name, matched by x value. A click pins them all, with a ghost pin on the others; Alt-click pins one card only.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom price text, taking precedence over valueFormat. Comparing instruments with versus uses signed percentages instead.
- `formatAxisValue` (`(value: number) => string`): Custom compact axis value text.
- `formatX` (`(value: string | number | Date) => string`): Custom x label text.
- `xType` (`'category' | 'number' | 'time'`): Override inferred x type. Use time for numeric Unix timestamps in milliseconds.
- `spotlight` (`boolean`): Highlight the inspected position in the plot background. Defaults to true.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
- `pillValue` (`'series' | 'stack'`): Read an individual series value (default) or its stacked height. Has no effect when the card has no stacked series.
- `decimate` (`boolean`): Defaults to true. Line and Area marks retain at most four observations per pixel column. Other marks draw every row; inspection and summaries always read the full data.
- `bleed` (`boolean`): Let marks reach the card edges with a soft fade.
- `headline` (`number`): Override the resting headline; an active range headline takes precedence.
## Depth chart: `DepthChartCard`
How much could trade at each price: buying on the left, selling on the right, and the gap between. Docs: https://liltui.vercel.app/finance/depth
```tsx
import { DepthChartCard } from '@lilt-ui/charts/finance';
```
### Complete examples
#### Depth card
```tsx
'use client';
import { DepthChartCard } from '@lilt-ui/charts/finance';
import '@lilt-ui/charts/styles.css';
const solBook = { "bids": [
{ "price": 182.28, "size": 1050 },
{ "price": 182.03, "size": 626 },
{ "price": 181.78, "size": 207 },
{ "price": 181.53, "size": 189 },
{ "price": 181.28, "size": 942 },
{ "price": 181.03, "size": 1284 },
{ "price": 180.78, "size": 991 },
{ "price": 180.53, "size": 561 },
{ "price": 180.28, "size": 476 },
{ "price": 180.03, "size": 1680 },
{ "price": 179.78, "size": 365 },
{ "price": 179.53, "size": 991 },
{ "price": 179.28, "size": 717 },
{ "price": 179.03, "size": 887 },
{ "price": 178.78, "size": 1610 },
{ "price": 178.53, "size": 376 },
], "asks": [
{ "price": 182.53, "size": 356 },
{ "price": 182.78, "size": 1793 },
{ "price": 183.03, "size": 1511 },
{ "price": 183.28, "size": 834 },
{ "price": 183.53, "size": 1049 },
{ "price": 183.78, "size": 794 },
{ "price": 184.03, "size": 387 },
{ "price": 184.28, "size": 201 },
{ "price": 184.53, "size": 611 },
{ "price": 184.78, "size": 871 },
{ "price": 185.03, "size": 830 },
{ "price": 185.28, "size": 1906 },
{ "price": 185.53, "size": 1119 },
{ "price": 185.78, "size": 447 },
{ "price": 186.03, "size": 200 },
{ "price": 186.28, "size": 1010 },
] };
export function Example() {
return (
);
}
```
### Data
```tsx
// Resting orders: a price and the size at it, in any order.
const book = {
bids: [
{ price: 182.28, size: 1050 },
{ price: 182.03, size: 626 },
],
asks: [
{ price: 182.53, size: 356 },
{ price: 182.78, size: 1793 },
],
};
```
Bids accumulate from the best (highest) bid down and asks from the best (lowest) ask up, so each curve shows how much size rests between the mid and a price. Orders at the same price merge. A crossed book, with a bid at or above an ask, throws rather than drawing a misleading spread. `depthLevels` returns the same cumulative levels, mid and spread for your own layouts.
### Hover
Hover a price to see how much could trade on that side before reaching it. The header keeps the midpoint, and the stats keep the gap and the totals on each side.
### Props
- `header` (`boolean`): False removes the title, midpoint and summary stats. Defaults to true.
- `aria-label` (`string`): Accessible name, independent of the visible title.
- `title` (`string`): Optional visible title. Also names the chart unless aria-label is set.
- `bids` (`{ price, size }[]`): Resting buy orders, in any order.
- `asks` (`{ price, size }[]`): Resting sell orders, in any order.
- `valueFormat` (`Intl.NumberFormatOptions`): Price format for the mid, spread and axis. Defaults to US dollars.
- `sizeFormat` (`Intl.NumberFormatOptions`): Size format for depth. Compact numbers by default.
- `height` (`number`): Plot height in pixels. Defaults to 220.
- `background` (`'dots' | 'grid' | 'lines' | 'none'`): Texture behind the depth areas.
- `axis` (`'minimal' | 'dots' | 'inline' | 'ruler' | 'classic' | 'segmented'`): Axis preset.
- `hoverStyle` (`'soft' | 'solid' | 'accent'`): How the pills look.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion.
- `depth` (`boolean`): Draws both sides' edges as lit tubes with a soft shadow; every step keeps its exact price.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): Headline number animation. Defaults to count; motion settings take precedence.
## Order book: `OrderBook`
Resting orders level by level, the best prices meeting in the middle. Docs: https://liltui.vercel.app/finance/order-book
```tsx
import { OrderBook } from '@lilt-ui/charts/finance';
```
### Complete examples
#### Order book
```tsx
'use client';
import { OrderBook } from '@lilt-ui/charts/finance';
import '@lilt-ui/charts/styles.css';
const solBook = { "bids": [
{ "price": 182.28, "size": 1050 },
{ "price": 182.03, "size": 626 },
{ "price": 181.78, "size": 207 },
{ "price": 181.53, "size": 189 },
{ "price": 181.28, "size": 942 },
{ "price": 181.03, "size": 1284 },
{ "price": 180.78, "size": 991 },
{ "price": 180.53, "size": 561 },
{ "price": 180.28, "size": 476 },
{ "price": 180.03, "size": 1680 },
{ "price": 179.78, "size": 365 },
{ "price": 179.53, "size": 991 },
{ "price": 179.28, "size": 717 },
{ "price": 179.03, "size": 887 },
{ "price": 178.78, "size": 1610 },
{ "price": 178.53, "size": 376 },
], "asks": [
{ "price": 182.53, "size": 356 },
{ "price": 182.78, "size": 1793 },
{ "price": 183.03, "size": 1511 },
{ "price": 183.28, "size": 834 },
{ "price": 183.53, "size": 1049 },
{ "price": 183.78, "size": 794 },
{ "price": 184.03, "size": 387 },
{ "price": 184.28, "size": 201 },
{ "price": 184.53, "size": 611 },
{ "price": 184.78, "size": 871 },
{ "price": 185.03, "size": 830 },
{ "price": 185.28, "size": 1906 },
{ "price": 185.53, "size": 1119 },
{ "price": 185.78, "size": 447 },
{ "price": 186.03, "size": 200 },
{ "price": 186.28, "size": 1010 },
] };
export function Example() {
return (
);
}
```
### Data
```tsx
const book = {
bids: [{ price: 182.28, size: 1050 } /* …resting buy orders */],
asks: [{ price: 182.53, size: 356 } /* …resting sell orders */],
};
```
The ladder shows the best `levels` on each side: asks above, highest first, and bids below, so the best prices meet at the spread row. Each level’s bar is its running total from the spread outward. Pass new `bids` and `asks` as the book updates and changed levels flash once; reduced motion turns that off.
### Hover
The ladder is a real table: a screen reader announces the caption, the asks, the spread and the bids row by row, with price as each row’s header.
### Props
- `header` (`boolean`): False removes the caption; column headings remain. Defaults to true.
- `aria-label` (`string`): Accessible name, independent of the visible title.
- `title` (`string`): Optional visible table caption. Also names the card unless aria-label is set.
- `bids` (`{ price, size }[]`): Resting buy orders, in any order.
- `asks` (`{ price, size }[]`): Resting sell orders, in any order.
- `levels` (`number`): Levels shown on each side of the spread. Defaults to 8.
- `depth` (`boolean`): Draws each level's bar as a solid block with a lit roof and a shaded end.
- `valueFormat` (`Intl.NumberFormatOptions`): Price format. Two decimals by default.
- `sizeFormat` (`Intl.NumberFormatOptions`): Size format. Compact numbers by default.
- `flash` (`boolean`): Highlight levels whose size changed. Defaults to true.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `motion` (`'auto' | 'none'`): None turns off decorative motion.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
## Portfolio chart: `PortfolioChartCard`
What an account is worth next to what went into it, and how far it sits below its best. Docs: https://liltui.vercel.app/finance/portfolio
```tsx
import { PortfolioChartCard } from '@lilt-ui/charts/finance';
```
### Complete examples
#### Portfolio card
```tsx
'use client';
import { PortfolioChartCard } from '@lilt-ui/charts/finance';
import '@lilt-ui/charts/styles.css';
const ranges = [
{ "id": "3m", "label": "3M", "data": [
{ "date": new Date('2026-06-28T00:00:00.000Z'), "value": 42710, "basis": 36250 },
{ "date": new Date('2026-06-29T00:00:00.000Z'), "value": 42719, "basis": 36250 },
{ "date": new Date('2026-06-30T00:00:00.000Z'), "value": 42517, "basis": 36250 },
{ "date": new Date('2026-07-01T00:00:00.000Z'), "value": 42662, "basis": 36250 },
{ "date": new Date('2026-07-02T00:00:00.000Z'), "value": 42741, "basis": 36250 },
{ "date": new Date('2026-07-03T00:00:00.000Z'), "value": 42941, "basis": 36250 },
{ "date": new Date('2026-07-04T00:00:00.000Z'), "value": 42816, "basis": 36250 },
{ "date": new Date('2026-07-05T00:00:00.000Z'), "value": 42908, "basis": 36250 },
{ "date": new Date('2026-07-06T00:00:00.000Z'), "value": 42875, "basis": 36250 },
{ "date": new Date('2026-07-07T00:00:00.000Z'), "value": 42977, "basis": 36250 },
{ "date": new Date('2026-07-08T00:00:00.000Z'), "value": 43045, "basis": 36250 },
{ "date": new Date('2026-07-09T00:00:00.000Z'), "value": 43017, "basis": 36250 },
{ "date": new Date('2026-07-10T00:00:00.000Z'), "value": 42863, "basis": 36250 },
{ "date": new Date('2026-07-11T00:00:00.000Z'), "value": 42841, "basis": 36250 },
{ "date": new Date('2026-07-12T00:00:00.000Z'), "value": 42818, "basis": 36250 },
{ "date": new Date('2026-07-13T00:00:00.000Z'), "value": 42689, "basis": 36250 },
{ "date": new Date('2026-07-14T00:00:00.000Z'), "value": 42630, "basis": 36250 },
{ "date": new Date('2026-07-15T00:00:00.000Z'), "value": 42604, "basis": 36250 },
{ "date": new Date('2026-07-16T00:00:00.000Z'), "value": 42795, "basis": 36250 },
{ "date": new Date('2026-07-17T00:00:00.000Z'), "value": 42813, "basis": 36250 },
{ "date": new Date('2026-07-18T00:00:00.000Z'), "value": 42697, "basis": 36250 },
{ "date": new Date('2026-07-19T00:00:00.000Z'), "value": 42589, "basis": 36250 },
{ "date": new Date('2026-07-20T00:00:00.000Z'), "value": 42734, "basis": 36250 },
{ "date": new Date('2026-07-21T00:00:00.000Z'), "value": 42656, "basis": 36250 },
{ "date": new Date('2026-07-22T00:00:00.000Z'), "value": 42863, "basis": 36250 },
{ "date": new Date('2026-07-23T00:00:00.000Z'), "value": 44128, "basis": 37500 },
{ "date": new Date('2026-07-24T00:00:00.000Z'), "value": 43949, "basis": 37500 },
{ "date": new Date('2026-07-25T00:00:00.000Z'), "value": 44035, "basis": 37500 },
{ "date": new Date('2026-07-26T00:00:00.000Z'), "value": 44299, "basis": 37500 },
{ "date": new Date('2026-07-27T00:00:00.000Z'), "value": 44133, "basis": 37500 },
{ "date": new Date('2026-07-28T00:00:00.000Z'), "value": 44302, "basis": 37500 },
{ "date": new Date('2026-07-29T00:00:00.000Z'), "value": 44375, "basis": 37500 },
{ "date": new Date('2026-07-30T00:00:00.000Z'), "value": 44549, "basis": 37500 },
{ "date": new Date('2026-07-31T00:00:00.000Z'), "value": 44594, "basis": 37500 },
{ "date": new Date('2026-08-01T00:00:00.000Z'), "value": 44571, "basis": 37500 },
{ "date": new Date('2026-08-02T00:00:00.000Z'), "value": 44817, "basis": 37500 },
{ "date": new Date('2026-08-03T00:00:00.000Z'), "value": 44855, "basis": 37500 },
{ "date": new Date('2026-08-04T00:00:00.000Z'), "value": 44722, "basis": 37500 },
{ "date": new Date('2026-08-05T00:00:00.000Z'), "value": 44527, "basis": 37500 },
{ "date": new Date('2026-08-06T00:00:00.000Z'), "value": 44281, "basis": 37500 },
{ "date": new Date('2026-08-07T00:00:00.000Z'), "value": 44200, "basis": 37500 },
{ "date": new Date('2026-08-08T00:00:00.000Z'), "value": 44422, "basis": 37500 },
{ "date": new Date('2026-08-09T00:00:00.000Z'), "value": 44417, "basis": 37500 },
{ "date": new Date('2026-08-10T00:00:00.000Z'), "value": 44546, "basis": 37500 },
{ "date": new Date('2026-08-11T00:00:00.000Z'), "value": 44315, "basis": 37500 },
{ "date": new Date('2026-08-12T00:00:00.000Z'), "value": 44541, "basis": 37500 },
{ "date": new Date('2026-08-13T00:00:00.000Z'), "value": 44370, "basis": 37500 },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "value": 44462, "basis": 37500 },
{ "date": new Date('2026-08-15T00:00:00.000Z'), "value": 44529, "basis": 37500 },
{ "date": new Date('2026-08-16T00:00:00.000Z'), "value": 44512, "basis": 37500 },
{ "date": new Date('2026-08-17T00:00:00.000Z'), "value": 44401, "basis": 37500 },
{ "date": new Date('2026-08-18T00:00:00.000Z'), "value": 44324, "basis": 37500 },
{ "date": new Date('2026-08-19T00:00:00.000Z'), "value": 44487, "basis": 37500 },
{ "date": new Date('2026-08-20T00:00:00.000Z'), "value": 44458, "basis": 37500 },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "value": 44572, "basis": 37500 },
{ "date": new Date('2026-08-22T00:00:00.000Z'), "value": 45765, "basis": 38750 },
{ "date": new Date('2026-08-23T00:00:00.000Z'), "value": 45703, "basis": 38750 },
{ "date": new Date('2026-08-24T00:00:00.000Z'), "value": 45593, "basis": 38750 },
{ "date": new Date('2026-08-25T00:00:00.000Z'), "value": 45574, "basis": 38750 },
{ "date": new Date('2026-08-26T00:00:00.000Z'), "value": 45844, "basis": 38750 },
{ "date": new Date('2026-08-27T00:00:00.000Z'), "value": 46039, "basis": 38750 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "value": 46045, "basis": 38750 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "value": 46162, "basis": 38750 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "value": 46426, "basis": 38750 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "value": 46321, "basis": 38750 },
{ "date": new Date('2026-09-01T00:00:00.000Z'), "value": 46289, "basis": 38750 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "value": 46377, "basis": 38750 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "value": 46127, "basis": 38750 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "value": 46212, "basis": 38750 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "value": 45955, "basis": 38750 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "value": 45727, "basis": 38750 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "value": 45976, "basis": 38750 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "value": 46276, "basis": 38750 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "value": 46246, "basis": 38750 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "value": 46287, "basis": 38750 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "value": 46552, "basis": 38750 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "value": 46434, "basis": 38750 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "value": 46303, "basis": 38750 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "value": 46420, "basis": 38750 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "value": 46322, "basis": 38750 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "value": 46492, "basis": 38750 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "value": 46447, "basis": 38750 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "value": 46223, "basis": 38750 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "value": 46545, "basis": 38750 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "value": 46680, "basis": 38750 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "value": 48153, "basis": 40000 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "value": 48372, "basis": 40000 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "value": 48428, "basis": 40000 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "value": 48478, "basis": 40000 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "value": 48438, "basis": 40000 },
] },
{ "id": "6m", "label": "6M", "data": [
{ "date": new Date('2026-03-28T00:00:00.000Z'), "value": 36200, "basis": 32500 },
{ "date": new Date('2026-03-29T00:00:00.000Z'), "value": 36116, "basis": 32500 },
{ "date": new Date('2026-03-30T00:00:00.000Z'), "value": 36118, "basis": 32500 },
{ "date": new Date('2026-03-31T00:00:00.000Z'), "value": 36163, "basis": 32500 },
{ "date": new Date('2026-04-01T00:00:00.000Z'), "value": 36272, "basis": 32500 },
{ "date": new Date('2026-04-02T00:00:00.000Z'), "value": 36238, "basis": 32500 },
{ "date": new Date('2026-04-03T00:00:00.000Z'), "value": 36150, "basis": 32500 },
{ "date": new Date('2026-04-04T00:00:00.000Z'), "value": 36319, "basis": 32500 },
{ "date": new Date('2026-04-05T00:00:00.000Z'), "value": 36148, "basis": 32500 },
{ "date": new Date('2026-04-06T00:00:00.000Z'), "value": 36117, "basis": 32500 },
{ "date": new Date('2026-04-07T00:00:00.000Z'), "value": 36239, "basis": 32500 },
{ "date": new Date('2026-04-08T00:00:00.000Z'), "value": 36097, "basis": 32500 },
{ "date": new Date('2026-04-09T00:00:00.000Z'), "value": 35959, "basis": 32500 },
{ "date": new Date('2026-04-10T00:00:00.000Z'), "value": 36222, "basis": 32500 },
{ "date": new Date('2026-04-11T00:00:00.000Z'), "value": 36057, "basis": 32500 },
{ "date": new Date('2026-04-12T00:00:00.000Z'), "value": 36097, "basis": 32500 },
{ "date": new Date('2026-04-13T00:00:00.000Z'), "value": 36079, "basis": 32500 },
{ "date": new Date('2026-04-14T00:00:00.000Z'), "value": 35939, "basis": 32500 },
{ "date": new Date('2026-04-15T00:00:00.000Z'), "value": 35835, "basis": 32500 },
{ "date": new Date('2026-04-16T00:00:00.000Z'), "value": 36093, "basis": 32500 },
{ "date": new Date('2026-04-17T00:00:00.000Z'), "value": 36075, "basis": 32500 },
{ "date": new Date('2026-04-18T00:00:00.000Z'), "value": 35887, "basis": 32500 },
{ "date": new Date('2026-04-19T00:00:00.000Z'), "value": 35973, "basis": 32500 },
{ "date": new Date('2026-04-20T00:00:00.000Z'), "value": 36093, "basis": 32500 },
{ "date": new Date('2026-04-21T00:00:00.000Z'), "value": 36251, "basis": 32500 },
{ "date": new Date('2026-04-22T00:00:00.000Z'), "value": 36292, "basis": 32500 },
{ "date": new Date('2026-04-23T00:00:00.000Z'), "value": 36196, "basis": 32500 },
{ "date": new Date('2026-04-24T00:00:00.000Z'), "value": 37328, "basis": 33750 },
{ "date": new Date('2026-04-25T00:00:00.000Z'), "value": 37539, "basis": 33750 },
{ "date": new Date('2026-04-26T00:00:00.000Z'), "value": 37797, "basis": 33750 },
{ "date": new Date('2026-04-27T00:00:00.000Z'), "value": 37834, "basis": 33750 },
{ "date": new Date('2026-04-28T00:00:00.000Z'), "value": 37675, "basis": 33750 },
{ "date": new Date('2026-04-29T00:00:00.000Z'), "value": 37797, "basis": 33750 },
{ "date": new Date('2026-04-30T00:00:00.000Z'), "value": 37828, "basis": 33750 },
{ "date": new Date('2026-05-01T00:00:00.000Z'), "value": 37769, "basis": 33750 },
{ "date": new Date('2026-05-02T00:00:00.000Z'), "value": 37610, "basis": 33750 },
{ "date": new Date('2026-05-03T00:00:00.000Z'), "value": 37637, "basis": 33750 },
{ "date": new Date('2026-05-04T00:00:00.000Z'), "value": 37909, "basis": 33750 },
{ "date": new Date('2026-05-05T00:00:00.000Z'), "value": 37952, "basis": 33750 },
{ "date": new Date('2026-05-06T00:00:00.000Z'), "value": 37829, "basis": 33750 },
{ "date": new Date('2026-05-07T00:00:00.000Z'), "value": 37732, "basis": 33750 },
{ "date": new Date('2026-05-08T00:00:00.000Z'), "value": 37989, "basis": 33750 },
{ "date": new Date('2026-05-09T00:00:00.000Z'), "value": 37876, "basis": 33750 },
{ "date": new Date('2026-05-10T00:00:00.000Z'), "value": 38052, "basis": 33750 },
{ "date": new Date('2026-05-11T00:00:00.000Z'), "value": 38198, "basis": 33750 },
{ "date": new Date('2026-05-12T00:00:00.000Z'), "value": 38279, "basis": 33750 },
{ "date": new Date('2026-05-13T00:00:00.000Z'), "value": 38068, "basis": 33750 },
{ "date": new Date('2026-05-14T00:00:00.000Z'), "value": 38068, "basis": 33750 },
{ "date": new Date('2026-05-15T00:00:00.000Z'), "value": 38311, "basis": 33750 },
{ "date": new Date('2026-05-16T00:00:00.000Z'), "value": 38097, "basis": 33750 },
{ "date": new Date('2026-05-17T00:00:00.000Z'), "value": 38263, "basis": 33750 },
{ "date": new Date('2026-05-18T00:00:00.000Z'), "value": 38296, "basis": 33750 },
{ "date": new Date('2026-05-19T00:00:00.000Z'), "value": 38358, "basis": 33750 },
{ "date": new Date('2026-05-20T00:00:00.000Z'), "value": 38364, "basis": 33750 },
{ "date": new Date('2026-05-21T00:00:00.000Z'), "value": 38308, "basis": 33750 },
{ "date": new Date('2026-05-22T00:00:00.000Z'), "value": 38421, "basis": 33750 },
{ "date": new Date('2026-05-23T00:00:00.000Z'), "value": 38635, "basis": 33750 },
{ "date": new Date('2026-05-24T00:00:00.000Z'), "value": 39801, "basis": 35000 },
{ "date": new Date('2026-05-25T00:00:00.000Z'), "value": 39766, "basis": 35000 },
{ "date": new Date('2026-05-26T00:00:00.000Z'), "value": 39545, "basis": 35000 },
{ "date": new Date('2026-05-27T00:00:00.000Z'), "value": 39468, "basis": 35000 },
{ "date": new Date('2026-05-28T00:00:00.000Z'), "value": 39665, "basis": 35000 },
{ "date": new Date('2026-05-29T00:00:00.000Z'), "value": 39699, "basis": 35000 },
{ "date": new Date('2026-05-30T00:00:00.000Z'), "value": 39917, "basis": 35000 },
{ "date": new Date('2026-05-31T00:00:00.000Z'), "value": 40201, "basis": 35000 },
{ "date": new Date('2026-06-01T00:00:00.000Z'), "value": 40239, "basis": 35000 },
{ "date": new Date('2026-06-02T00:00:00.000Z'), "value": 40352, "basis": 35000 },
{ "date": new Date('2026-06-03T00:00:00.000Z'), "value": 40169, "basis": 35000 },
{ "date": new Date('2026-06-04T00:00:00.000Z'), "value": 40001, "basis": 35000 },
{ "date": new Date('2026-06-05T00:00:00.000Z'), "value": 40038, "basis": 35000 },
{ "date": new Date('2026-06-06T00:00:00.000Z'), "value": 40079, "basis": 35000 },
{ "date": new Date('2026-06-07T00:00:00.000Z'), "value": 40132, "basis": 35000 },
{ "date": new Date('2026-06-08T00:00:00.000Z'), "value": 40238, "basis": 35000 },
{ "date": new Date('2026-06-09T00:00:00.000Z'), "value": 40231, "basis": 35000 },
{ "date": new Date('2026-06-10T00:00:00.000Z'), "value": 40008, "basis": 35000 },
{ "date": new Date('2026-06-11T00:00:00.000Z'), "value": 40075, "basis": 35000 },
{ "date": new Date('2026-06-12T00:00:00.000Z'), "value": 40364, "basis": 35000 },
{ "date": new Date('2026-06-13T00:00:00.000Z'), "value": 40194, "basis": 35000 },
{ "date": new Date('2026-06-14T00:00:00.000Z'), "value": 40048, "basis": 35000 },
{ "date": new Date('2026-06-15T00:00:00.000Z'), "value": 40011, "basis": 35000 },
{ "date": new Date('2026-06-16T00:00:00.000Z'), "value": 40240, "basis": 35000 },
{ "date": new Date('2026-06-17T00:00:00.000Z'), "value": 40503, "basis": 35000 },
{ "date": new Date('2026-06-18T00:00:00.000Z'), "value": 40739, "basis": 35000 },
{ "date": new Date('2026-06-19T00:00:00.000Z'), "value": 40757, "basis": 35000 },
{ "date": new Date('2026-06-20T00:00:00.000Z'), "value": 40540, "basis": 35000 },
{ "date": new Date('2026-06-21T00:00:00.000Z'), "value": 40714, "basis": 35000 },
{ "date": new Date('2026-06-22T00:00:00.000Z'), "value": 40662, "basis": 35000 },
{ "date": new Date('2026-06-23T00:00:00.000Z'), "value": 42153, "basis": 36250 },
{ "date": new Date('2026-06-24T00:00:00.000Z'), "value": 42298, "basis": 36250 },
{ "date": new Date('2026-06-25T00:00:00.000Z'), "value": 42093, "basis": 36250 },
{ "date": new Date('2026-06-26T00:00:00.000Z'), "value": 42181, "basis": 36250 },
{ "date": new Date('2026-06-27T00:00:00.000Z'), "value": 42416, "basis": 36250 },
{ "date": new Date('2026-06-28T00:00:00.000Z'), "value": 42710, "basis": 36250 },
{ "date": new Date('2026-06-29T00:00:00.000Z'), "value": 42719, "basis": 36250 },
{ "date": new Date('2026-06-30T00:00:00.000Z'), "value": 42517, "basis": 36250 },
{ "date": new Date('2026-07-01T00:00:00.000Z'), "value": 42662, "basis": 36250 },
{ "date": new Date('2026-07-02T00:00:00.000Z'), "value": 42741, "basis": 36250 },
{ "date": new Date('2026-07-03T00:00:00.000Z'), "value": 42941, "basis": 36250 },
{ "date": new Date('2026-07-04T00:00:00.000Z'), "value": 42816, "basis": 36250 },
{ "date": new Date('2026-07-05T00:00:00.000Z'), "value": 42908, "basis": 36250 },
{ "date": new Date('2026-07-06T00:00:00.000Z'), "value": 42875, "basis": 36250 },
{ "date": new Date('2026-07-07T00:00:00.000Z'), "value": 42977, "basis": 36250 },
{ "date": new Date('2026-07-08T00:00:00.000Z'), "value": 43045, "basis": 36250 },
{ "date": new Date('2026-07-09T00:00:00.000Z'), "value": 43017, "basis": 36250 },
{ "date": new Date('2026-07-10T00:00:00.000Z'), "value": 42863, "basis": 36250 },
{ "date": new Date('2026-07-11T00:00:00.000Z'), "value": 42841, "basis": 36250 },
{ "date": new Date('2026-07-12T00:00:00.000Z'), "value": 42818, "basis": 36250 },
{ "date": new Date('2026-07-13T00:00:00.000Z'), "value": 42689, "basis": 36250 },
{ "date": new Date('2026-07-14T00:00:00.000Z'), "value": 42630, "basis": 36250 },
{ "date": new Date('2026-07-15T00:00:00.000Z'), "value": 42604, "basis": 36250 },
{ "date": new Date('2026-07-16T00:00:00.000Z'), "value": 42795, "basis": 36250 },
{ "date": new Date('2026-07-17T00:00:00.000Z'), "value": 42813, "basis": 36250 },
{ "date": new Date('2026-07-18T00:00:00.000Z'), "value": 42697, "basis": 36250 },
{ "date": new Date('2026-07-19T00:00:00.000Z'), "value": 42589, "basis": 36250 },
{ "date": new Date('2026-07-20T00:00:00.000Z'), "value": 42734, "basis": 36250 },
{ "date": new Date('2026-07-21T00:00:00.000Z'), "value": 42656, "basis": 36250 },
{ "date": new Date('2026-07-22T00:00:00.000Z'), "value": 42863, "basis": 36250 },
{ "date": new Date('2026-07-23T00:00:00.000Z'), "value": 44128, "basis": 37500 },
{ "date": new Date('2026-07-24T00:00:00.000Z'), "value": 43949, "basis": 37500 },
{ "date": new Date('2026-07-25T00:00:00.000Z'), "value": 44035, "basis": 37500 },
{ "date": new Date('2026-07-26T00:00:00.000Z'), "value": 44299, "basis": 37500 },
{ "date": new Date('2026-07-27T00:00:00.000Z'), "value": 44133, "basis": 37500 },
{ "date": new Date('2026-07-28T00:00:00.000Z'), "value": 44302, "basis": 37500 },
{ "date": new Date('2026-07-29T00:00:00.000Z'), "value": 44375, "basis": 37500 },
{ "date": new Date('2026-07-30T00:00:00.000Z'), "value": 44549, "basis": 37500 },
{ "date": new Date('2026-07-31T00:00:00.000Z'), "value": 44594, "basis": 37500 },
{ "date": new Date('2026-08-01T00:00:00.000Z'), "value": 44571, "basis": 37500 },
{ "date": new Date('2026-08-02T00:00:00.000Z'), "value": 44817, "basis": 37500 },
{ "date": new Date('2026-08-03T00:00:00.000Z'), "value": 44855, "basis": 37500 },
{ "date": new Date('2026-08-04T00:00:00.000Z'), "value": 44722, "basis": 37500 },
{ "date": new Date('2026-08-05T00:00:00.000Z'), "value": 44527, "basis": 37500 },
{ "date": new Date('2026-08-06T00:00:00.000Z'), "value": 44281, "basis": 37500 },
{ "date": new Date('2026-08-07T00:00:00.000Z'), "value": 44200, "basis": 37500 },
{ "date": new Date('2026-08-08T00:00:00.000Z'), "value": 44422, "basis": 37500 },
{ "date": new Date('2026-08-09T00:00:00.000Z'), "value": 44417, "basis": 37500 },
{ "date": new Date('2026-08-10T00:00:00.000Z'), "value": 44546, "basis": 37500 },
{ "date": new Date('2026-08-11T00:00:00.000Z'), "value": 44315, "basis": 37500 },
{ "date": new Date('2026-08-12T00:00:00.000Z'), "value": 44541, "basis": 37500 },
{ "date": new Date('2026-08-13T00:00:00.000Z'), "value": 44370, "basis": 37500 },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "value": 44462, "basis": 37500 },
{ "date": new Date('2026-08-15T00:00:00.000Z'), "value": 44529, "basis": 37500 },
{ "date": new Date('2026-08-16T00:00:00.000Z'), "value": 44512, "basis": 37500 },
{ "date": new Date('2026-08-17T00:00:00.000Z'), "value": 44401, "basis": 37500 },
{ "date": new Date('2026-08-18T00:00:00.000Z'), "value": 44324, "basis": 37500 },
{ "date": new Date('2026-08-19T00:00:00.000Z'), "value": 44487, "basis": 37500 },
{ "date": new Date('2026-08-20T00:00:00.000Z'), "value": 44458, "basis": 37500 },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "value": 44572, "basis": 37500 },
{ "date": new Date('2026-08-22T00:00:00.000Z'), "value": 45765, "basis": 38750 },
{ "date": new Date('2026-08-23T00:00:00.000Z'), "value": 45703, "basis": 38750 },
{ "date": new Date('2026-08-24T00:00:00.000Z'), "value": 45593, "basis": 38750 },
{ "date": new Date('2026-08-25T00:00:00.000Z'), "value": 45574, "basis": 38750 },
{ "date": new Date('2026-08-26T00:00:00.000Z'), "value": 45844, "basis": 38750 },
{ "date": new Date('2026-08-27T00:00:00.000Z'), "value": 46039, "basis": 38750 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "value": 46045, "basis": 38750 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "value": 46162, "basis": 38750 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "value": 46426, "basis": 38750 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "value": 46321, "basis": 38750 },
{ "date": new Date('2026-09-01T00:00:00.000Z'), "value": 46289, "basis": 38750 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "value": 46377, "basis": 38750 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "value": 46127, "basis": 38750 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "value": 46212, "basis": 38750 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "value": 45955, "basis": 38750 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "value": 45727, "basis": 38750 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "value": 45976, "basis": 38750 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "value": 46276, "basis": 38750 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "value": 46246, "basis": 38750 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "value": 46287, "basis": 38750 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "value": 46552, "basis": 38750 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "value": 46434, "basis": 38750 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "value": 46303, "basis": 38750 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "value": 46420, "basis": 38750 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "value": 46322, "basis": 38750 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "value": 46492, "basis": 38750 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "value": 46447, "basis": 38750 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "value": 46223, "basis": 38750 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "value": 46545, "basis": 38750 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "value": 46680, "basis": 38750 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "value": 48153, "basis": 40000 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "value": 48372, "basis": 40000 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "value": 48428, "basis": 40000 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "value": 48478, "basis": 40000 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "value": 48438, "basis": 40000 },
] },
{ "id": "1y", "label": "1Y", "data": [
{ "date": new Date('2025-09-26T00:00:00.000Z'), "value": 25084, "basis": 25000 },
{ "date": new Date('2025-09-27T00:00:00.000Z'), "value": 25196, "basis": 25000 },
{ "date": new Date('2025-09-28T00:00:00.000Z'), "value": 25127, "basis": 25000 },
{ "date": new Date('2025-09-29T00:00:00.000Z'), "value": 25189, "basis": 25000 },
{ "date": new Date('2025-09-30T00:00:00.000Z'), "value": 25076, "basis": 25000 },
{ "date": new Date('2025-10-01T00:00:00.000Z'), "value": 25129, "basis": 25000 },
{ "date": new Date('2025-10-02T00:00:00.000Z'), "value": 25223, "basis": 25000 },
{ "date": new Date('2025-10-03T00:00:00.000Z'), "value": 25232, "basis": 25000 },
{ "date": new Date('2025-10-04T00:00:00.000Z'), "value": 25388, "basis": 25000 },
{ "date": new Date('2025-10-05T00:00:00.000Z'), "value": 25322, "basis": 25000 },
{ "date": new Date('2025-10-06T00:00:00.000Z'), "value": 25437, "basis": 25000 },
{ "date": new Date('2025-10-07T00:00:00.000Z'), "value": 25539, "basis": 25000 },
{ "date": new Date('2025-10-08T00:00:00.000Z'), "value": 25615, "basis": 25000 },
{ "date": new Date('2025-10-09T00:00:00.000Z'), "value": 25476, "basis": 25000 },
{ "date": new Date('2025-10-10T00:00:00.000Z'), "value": 25488, "basis": 25000 },
{ "date": new Date('2025-10-11T00:00:00.000Z'), "value": 25445, "basis": 25000 },
{ "date": new Date('2025-10-12T00:00:00.000Z'), "value": 25599, "basis": 25000 },
{ "date": new Date('2025-10-13T00:00:00.000Z'), "value": 25551, "basis": 25000 },
{ "date": new Date('2025-10-14T00:00:00.000Z'), "value": 25659, "basis": 25000 },
{ "date": new Date('2025-10-15T00:00:00.000Z'), "value": 25757, "basis": 25000 },
{ "date": new Date('2025-10-16T00:00:00.000Z'), "value": 25697, "basis": 25000 },
{ "date": new Date('2025-10-17T00:00:00.000Z'), "value": 25560, "basis": 25000 },
{ "date": new Date('2025-10-18T00:00:00.000Z'), "value": 25680, "basis": 25000 },
{ "date": new Date('2025-10-19T00:00:00.000Z'), "value": 25606, "basis": 25000 },
{ "date": new Date('2025-10-20T00:00:00.000Z'), "value": 25554, "basis": 25000 },
{ "date": new Date('2025-10-21T00:00:00.000Z'), "value": 25451, "basis": 25000 },
{ "date": new Date('2025-10-22T00:00:00.000Z'), "value": 25464, "basis": 25000 },
{ "date": new Date('2025-10-23T00:00:00.000Z'), "value": 25650, "basis": 25000 },
{ "date": new Date('2025-10-24T00:00:00.000Z'), "value": 25588, "basis": 25000 },
{ "date": new Date('2025-10-25T00:00:00.000Z'), "value": 25472, "basis": 25000 },
{ "date": new Date('2025-10-26T00:00:00.000Z'), "value": 26867, "basis": 26250 },
{ "date": new Date('2025-10-27T00:00:00.000Z'), "value": 26827, "basis": 26250 },
{ "date": new Date('2025-10-28T00:00:00.000Z'), "value": 26819, "basis": 26250 },
{ "date": new Date('2025-10-29T00:00:00.000Z'), "value": 27013, "basis": 26250 },
{ "date": new Date('2025-10-30T00:00:00.000Z'), "value": 26957, "basis": 26250 },
{ "date": new Date('2025-10-31T00:00:00.000Z'), "value": 26941, "basis": 26250 },
{ "date": new Date('2025-11-01T00:00:00.000Z'), "value": 26867, "basis": 26250 },
{ "date": new Date('2025-11-02T00:00:00.000Z'), "value": 27020, "basis": 26250 },
{ "date": new Date('2025-11-03T00:00:00.000Z'), "value": 27122, "basis": 26250 },
{ "date": new Date('2025-11-04T00:00:00.000Z'), "value": 27280, "basis": 26250 },
{ "date": new Date('2025-11-05T00:00:00.000Z'), "value": 27309, "basis": 26250 },
{ "date": new Date('2025-11-06T00:00:00.000Z'), "value": 27442, "basis": 26250 },
{ "date": new Date('2025-11-07T00:00:00.000Z'), "value": 27519, "basis": 26250 },
{ "date": new Date('2025-11-08T00:00:00.000Z'), "value": 27415, "basis": 26250 },
{ "date": new Date('2025-11-09T00:00:00.000Z'), "value": 27488, "basis": 26250 },
{ "date": new Date('2025-11-10T00:00:00.000Z'), "value": 27541, "basis": 26250 },
{ "date": new Date('2025-11-11T00:00:00.000Z'), "value": 27500, "basis": 26250 },
{ "date": new Date('2025-11-12T00:00:00.000Z'), "value": 27624, "basis": 26250 },
{ "date": new Date('2025-11-13T00:00:00.000Z'), "value": 27688, "basis": 26250 },
{ "date": new Date('2025-11-14T00:00:00.000Z'), "value": 27536, "basis": 26250 },
{ "date": new Date('2025-11-15T00:00:00.000Z'), "value": 27715, "basis": 26250 },
{ "date": new Date('2025-11-16T00:00:00.000Z'), "value": 27683, "basis": 26250 },
{ "date": new Date('2025-11-17T00:00:00.000Z'), "value": 27654, "basis": 26250 },
{ "date": new Date('2025-11-18T00:00:00.000Z'), "value": 27814, "basis": 26250 },
{ "date": new Date('2025-11-19T00:00:00.000Z'), "value": 27748, "basis": 26250 },
{ "date": new Date('2025-11-20T00:00:00.000Z'), "value": 27656, "basis": 26250 },
{ "date": new Date('2025-11-21T00:00:00.000Z'), "value": 27801, "basis": 26250 },
{ "date": new Date('2025-11-22T00:00:00.000Z'), "value": 27746, "basis": 26250 },
{ "date": new Date('2025-11-23T00:00:00.000Z'), "value": 27951, "basis": 26250 },
{ "date": new Date('2025-11-24T00:00:00.000Z'), "value": 27799, "basis": 26250 },
{ "date": new Date('2025-11-25T00:00:00.000Z'), "value": 29019, "basis": 27500 },
{ "date": new Date('2025-11-26T00:00:00.000Z'), "value": 29143, "basis": 27500 },
{ "date": new Date('2025-11-27T00:00:00.000Z'), "value": 29099, "basis": 27500 },
{ "date": new Date('2025-11-28T00:00:00.000Z'), "value": 29186, "basis": 27500 },
{ "date": new Date('2025-11-29T00:00:00.000Z'), "value": 29051, "basis": 27500 },
{ "date": new Date('2025-11-30T00:00:00.000Z'), "value": 28919, "basis": 27500 },
{ "date": new Date('2025-12-01T00:00:00.000Z'), "value": 29033, "basis": 27500 },
{ "date": new Date('2025-12-02T00:00:00.000Z'), "value": 29069, "basis": 27500 },
{ "date": new Date('2025-12-03T00:00:00.000Z'), "value": 29002, "basis": 27500 },
{ "date": new Date('2025-12-04T00:00:00.000Z'), "value": 29190, "basis": 27500 },
{ "date": new Date('2025-12-05T00:00:00.000Z'), "value": 29045, "basis": 27500 },
{ "date": new Date('2025-12-06T00:00:00.000Z'), "value": 29160, "basis": 27500 },
{ "date": new Date('2025-12-07T00:00:00.000Z'), "value": 29358, "basis": 27500 },
{ "date": new Date('2025-12-08T00:00:00.000Z'), "value": 29303, "basis": 27500 },
{ "date": new Date('2025-12-09T00:00:00.000Z'), "value": 29342, "basis": 27500 },
{ "date": new Date('2025-12-10T00:00:00.000Z'), "value": 29504, "basis": 27500 },
{ "date": new Date('2025-12-11T00:00:00.000Z'), "value": 29664, "basis": 27500 },
{ "date": new Date('2025-12-12T00:00:00.000Z'), "value": 29721, "basis": 27500 },
{ "date": new Date('2025-12-13T00:00:00.000Z'), "value": 29924, "basis": 27500 },
{ "date": new Date('2025-12-14T00:00:00.000Z'), "value": 30030, "basis": 27500 },
{ "date": new Date('2025-12-15T00:00:00.000Z'), "value": 30072, "basis": 27500 },
{ "date": new Date('2025-12-16T00:00:00.000Z'), "value": 29947, "basis": 27500 },
{ "date": new Date('2025-12-17T00:00:00.000Z'), "value": 29894, "basis": 27500 },
{ "date": new Date('2025-12-18T00:00:00.000Z'), "value": 29932, "basis": 27500 },
{ "date": new Date('2025-12-19T00:00:00.000Z'), "value": 29825, "basis": 27500 },
{ "date": new Date('2025-12-20T00:00:00.000Z'), "value": 29755, "basis": 27500 },
{ "date": new Date('2025-12-21T00:00:00.000Z'), "value": 29885, "basis": 27500 },
{ "date": new Date('2025-12-22T00:00:00.000Z'), "value": 29772, "basis": 27500 },
{ "date": new Date('2025-12-23T00:00:00.000Z'), "value": 29636, "basis": 27500 },
{ "date": new Date('2025-12-24T00:00:00.000Z'), "value": 29596, "basis": 27500 },
{ "date": new Date('2025-12-25T00:00:00.000Z'), "value": 30996, "basis": 28750 },
{ "date": new Date('2025-12-26T00:00:00.000Z'), "value": 31082, "basis": 28750 },
{ "date": new Date('2025-12-27T00:00:00.000Z'), "value": 31075, "basis": 28750 },
{ "date": new Date('2025-12-28T00:00:00.000Z'), "value": 30940, "basis": 28750 },
{ "date": new Date('2025-12-29T00:00:00.000Z'), "value": 30884, "basis": 28750 },
{ "date": new Date('2025-12-30T00:00:00.000Z'), "value": 31095, "basis": 28750 },
{ "date": new Date('2025-12-31T00:00:00.000Z'), "value": 31053, "basis": 28750 },
{ "date": new Date('2026-01-01T00:00:00.000Z'), "value": 31162, "basis": 28750 },
{ "date": new Date('2026-01-02T00:00:00.000Z'), "value": 31289, "basis": 28750 },
{ "date": new Date('2026-01-03T00:00:00.000Z'), "value": 31156, "basis": 28750 },
{ "date": new Date('2026-01-04T00:00:00.000Z'), "value": 31299, "basis": 28750 },
{ "date": new Date('2026-01-05T00:00:00.000Z'), "value": 31502, "basis": 28750 },
{ "date": new Date('2026-01-06T00:00:00.000Z'), "value": 31574, "basis": 28750 },
{ "date": new Date('2026-01-07T00:00:00.000Z'), "value": 31443, "basis": 28750 },
{ "date": new Date('2026-01-08T00:00:00.000Z'), "value": 31415, "basis": 28750 },
{ "date": new Date('2026-01-09T00:00:00.000Z'), "value": 31403, "basis": 28750 },
{ "date": new Date('2026-01-10T00:00:00.000Z'), "value": 31249, "basis": 28750 },
{ "date": new Date('2026-01-11T00:00:00.000Z'), "value": 31245, "basis": 28750 },
{ "date": new Date('2026-01-12T00:00:00.000Z'), "value": 31443, "basis": 28750 },
{ "date": new Date('2026-01-13T00:00:00.000Z'), "value": 31394, "basis": 28750 },
{ "date": new Date('2026-01-14T00:00:00.000Z'), "value": 31531, "basis": 28750 },
{ "date": new Date('2026-01-15T00:00:00.000Z'), "value": 31376, "basis": 28750 },
{ "date": new Date('2026-01-16T00:00:00.000Z'), "value": 31533, "basis": 28750 },
{ "date": new Date('2026-01-17T00:00:00.000Z'), "value": 31398, "basis": 28750 },
{ "date": new Date('2026-01-18T00:00:00.000Z'), "value": 31431, "basis": 28750 },
{ "date": new Date('2026-01-19T00:00:00.000Z'), "value": 31593, "basis": 28750 },
{ "date": new Date('2026-01-20T00:00:00.000Z'), "value": 31502, "basis": 28750 },
{ "date": new Date('2026-01-21T00:00:00.000Z'), "value": 31570, "basis": 28750 },
{ "date": new Date('2026-01-22T00:00:00.000Z'), "value": 31434, "basis": 28750 },
{ "date": new Date('2026-01-23T00:00:00.000Z'), "value": 31407, "basis": 28750 },
{ "date": new Date('2026-01-24T00:00:00.000Z'), "value": 32756, "basis": 30000 },
{ "date": new Date('2026-01-25T00:00:00.000Z'), "value": 32681, "basis": 30000 },
{ "date": new Date('2026-01-26T00:00:00.000Z'), "value": 32787, "basis": 30000 },
{ "date": new Date('2026-01-27T00:00:00.000Z'), "value": 32706, "basis": 30000 },
{ "date": new Date('2026-01-28T00:00:00.000Z'), "value": 32630, "basis": 30000 },
{ "date": new Date('2026-01-29T00:00:00.000Z'), "value": 32865, "basis": 30000 },
{ "date": new Date('2026-01-30T00:00:00.000Z'), "value": 32956, "basis": 30000 },
{ "date": new Date('2026-01-31T00:00:00.000Z'), "value": 32965, "basis": 30000 },
{ "date": new Date('2026-02-01T00:00:00.000Z'), "value": 33099, "basis": 30000 },
{ "date": new Date('2026-02-02T00:00:00.000Z'), "value": 32930, "basis": 30000 },
{ "date": new Date('2026-02-03T00:00:00.000Z'), "value": 33011, "basis": 30000 },
{ "date": new Date('2026-02-04T00:00:00.000Z'), "value": 33107, "basis": 30000 },
{ "date": new Date('2026-02-05T00:00:00.000Z'), "value": 32930, "basis": 30000 },
{ "date": new Date('2026-02-06T00:00:00.000Z'), "value": 32808, "basis": 30000 },
{ "date": new Date('2026-02-07T00:00:00.000Z'), "value": 32766, "basis": 30000 },
{ "date": new Date('2026-02-08T00:00:00.000Z'), "value": 32725, "basis": 30000 },
{ "date": new Date('2026-02-09T00:00:00.000Z'), "value": 32815, "basis": 30000 },
{ "date": new Date('2026-02-10T00:00:00.000Z'), "value": 33036, "basis": 30000 },
{ "date": new Date('2026-02-11T00:00:00.000Z'), "value": 33106, "basis": 30000 },
{ "date": new Date('2026-02-12T00:00:00.000Z'), "value": 33295, "basis": 30000 },
{ "date": new Date('2026-02-13T00:00:00.000Z'), "value": 33443, "basis": 30000 },
{ "date": new Date('2026-02-14T00:00:00.000Z'), "value": 33379, "basis": 30000 },
{ "date": new Date('2026-02-15T00:00:00.000Z'), "value": 33220, "basis": 30000 },
{ "date": new Date('2026-02-16T00:00:00.000Z'), "value": 33107, "basis": 30000 },
{ "date": new Date('2026-02-17T00:00:00.000Z'), "value": 32940, "basis": 30000 },
{ "date": new Date('2026-02-18T00:00:00.000Z'), "value": 32852, "basis": 30000 },
{ "date": new Date('2026-02-19T00:00:00.000Z'), "value": 33049, "basis": 30000 },
{ "date": new Date('2026-02-20T00:00:00.000Z'), "value": 33058, "basis": 30000 },
{ "date": new Date('2026-02-21T00:00:00.000Z'), "value": 32891, "basis": 30000 },
{ "date": new Date('2026-02-22T00:00:00.000Z'), "value": 33039, "basis": 30000 },
{ "date": new Date('2026-02-23T00:00:00.000Z'), "value": 34358, "basis": 31250 },
{ "date": new Date('2026-02-24T00:00:00.000Z'), "value": 34294, "basis": 31250 },
{ "date": new Date('2026-02-25T00:00:00.000Z'), "value": 34500, "basis": 31250 },
{ "date": new Date('2026-02-26T00:00:00.000Z'), "value": 34655, "basis": 31250 },
{ "date": new Date('2026-02-27T00:00:00.000Z'), "value": 34898, "basis": 31250 },
{ "date": new Date('2026-02-28T00:00:00.000Z'), "value": 34785, "basis": 31250 },
{ "date": new Date('2026-03-01T00:00:00.000Z'), "value": 34714, "basis": 31250 },
{ "date": new Date('2026-03-02T00:00:00.000Z'), "value": 34883, "basis": 31250 },
{ "date": new Date('2026-03-03T00:00:00.000Z'), "value": 34812, "basis": 31250 },
{ "date": new Date('2026-03-04T00:00:00.000Z'), "value": 34749, "basis": 31250 },
{ "date": new Date('2026-03-05T00:00:00.000Z'), "value": 34901, "basis": 31250 },
{ "date": new Date('2026-03-06T00:00:00.000Z'), "value": 34707, "basis": 31250 },
{ "date": new Date('2026-03-07T00:00:00.000Z'), "value": 34810, "basis": 31250 },
{ "date": new Date('2026-03-08T00:00:00.000Z'), "value": 34855, "basis": 31250 },
{ "date": new Date('2026-03-09T00:00:00.000Z'), "value": 34782, "basis": 31250 },
{ "date": new Date('2026-03-10T00:00:00.000Z'), "value": 34698, "basis": 31250 },
{ "date": new Date('2026-03-11T00:00:00.000Z'), "value": 34803, "basis": 31250 },
{ "date": new Date('2026-03-12T00:00:00.000Z'), "value": 34975, "basis": 31250 },
{ "date": new Date('2026-03-13T00:00:00.000Z'), "value": 35035, "basis": 31250 },
{ "date": new Date('2026-03-14T00:00:00.000Z'), "value": 35115, "basis": 31250 },
{ "date": new Date('2026-03-15T00:00:00.000Z'), "value": 35225, "basis": 31250 },
{ "date": new Date('2026-03-16T00:00:00.000Z'), "value": 35223, "basis": 31250 },
{ "date": new Date('2026-03-17T00:00:00.000Z'), "value": 35286, "basis": 31250 },
{ "date": new Date('2026-03-18T00:00:00.000Z'), "value": 35180, "basis": 31250 },
{ "date": new Date('2026-03-19T00:00:00.000Z'), "value": 35031, "basis": 31250 },
{ "date": new Date('2026-03-20T00:00:00.000Z'), "value": 35004, "basis": 31250 },
{ "date": new Date('2026-03-21T00:00:00.000Z'), "value": 35034, "basis": 31250 },
{ "date": new Date('2026-03-22T00:00:00.000Z'), "value": 34867, "basis": 31250 },
{ "date": new Date('2026-03-23T00:00:00.000Z'), "value": 34947, "basis": 31250 },
{ "date": new Date('2026-03-24T00:00:00.000Z'), "value": 34958, "basis": 31250 },
{ "date": new Date('2026-03-25T00:00:00.000Z'), "value": 36224, "basis": 32500 },
{ "date": new Date('2026-03-26T00:00:00.000Z'), "value": 36202, "basis": 32500 },
{ "date": new Date('2026-03-27T00:00:00.000Z'), "value": 36235, "basis": 32500 },
{ "date": new Date('2026-03-28T00:00:00.000Z'), "value": 36200, "basis": 32500 },
{ "date": new Date('2026-03-29T00:00:00.000Z'), "value": 36116, "basis": 32500 },
{ "date": new Date('2026-03-30T00:00:00.000Z'), "value": 36118, "basis": 32500 },
{ "date": new Date('2026-03-31T00:00:00.000Z'), "value": 36163, "basis": 32500 },
{ "date": new Date('2026-04-01T00:00:00.000Z'), "value": 36272, "basis": 32500 },
{ "date": new Date('2026-04-02T00:00:00.000Z'), "value": 36238, "basis": 32500 },
{ "date": new Date('2026-04-03T00:00:00.000Z'), "value": 36150, "basis": 32500 },
{ "date": new Date('2026-04-04T00:00:00.000Z'), "value": 36319, "basis": 32500 },
{ "date": new Date('2026-04-05T00:00:00.000Z'), "value": 36148, "basis": 32500 },
{ "date": new Date('2026-04-06T00:00:00.000Z'), "value": 36117, "basis": 32500 },
{ "date": new Date('2026-04-07T00:00:00.000Z'), "value": 36239, "basis": 32500 },
{ "date": new Date('2026-04-08T00:00:00.000Z'), "value": 36097, "basis": 32500 },
{ "date": new Date('2026-04-09T00:00:00.000Z'), "value": 35959, "basis": 32500 },
{ "date": new Date('2026-04-10T00:00:00.000Z'), "value": 36222, "basis": 32500 },
{ "date": new Date('2026-04-11T00:00:00.000Z'), "value": 36057, "basis": 32500 },
{ "date": new Date('2026-04-12T00:00:00.000Z'), "value": 36097, "basis": 32500 },
{ "date": new Date('2026-04-13T00:00:00.000Z'), "value": 36079, "basis": 32500 },
{ "date": new Date('2026-04-14T00:00:00.000Z'), "value": 35939, "basis": 32500 },
{ "date": new Date('2026-04-15T00:00:00.000Z'), "value": 35835, "basis": 32500 },
{ "date": new Date('2026-04-16T00:00:00.000Z'), "value": 36093, "basis": 32500 },
{ "date": new Date('2026-04-17T00:00:00.000Z'), "value": 36075, "basis": 32500 },
{ "date": new Date('2026-04-18T00:00:00.000Z'), "value": 35887, "basis": 32500 },
{ "date": new Date('2026-04-19T00:00:00.000Z'), "value": 35973, "basis": 32500 },
{ "date": new Date('2026-04-20T00:00:00.000Z'), "value": 36093, "basis": 32500 },
{ "date": new Date('2026-04-21T00:00:00.000Z'), "value": 36251, "basis": 32500 },
{ "date": new Date('2026-04-22T00:00:00.000Z'), "value": 36292, "basis": 32500 },
{ "date": new Date('2026-04-23T00:00:00.000Z'), "value": 36196, "basis": 32500 },
{ "date": new Date('2026-04-24T00:00:00.000Z'), "value": 37328, "basis": 33750 },
{ "date": new Date('2026-04-25T00:00:00.000Z'), "value": 37539, "basis": 33750 },
{ "date": new Date('2026-04-26T00:00:00.000Z'), "value": 37797, "basis": 33750 },
{ "date": new Date('2026-04-27T00:00:00.000Z'), "value": 37834, "basis": 33750 },
{ "date": new Date('2026-04-28T00:00:00.000Z'), "value": 37675, "basis": 33750 },
{ "date": new Date('2026-04-29T00:00:00.000Z'), "value": 37797, "basis": 33750 },
{ "date": new Date('2026-04-30T00:00:00.000Z'), "value": 37828, "basis": 33750 },
{ "date": new Date('2026-05-01T00:00:00.000Z'), "value": 37769, "basis": 33750 },
{ "date": new Date('2026-05-02T00:00:00.000Z'), "value": 37610, "basis": 33750 },
{ "date": new Date('2026-05-03T00:00:00.000Z'), "value": 37637, "basis": 33750 },
{ "date": new Date('2026-05-04T00:00:00.000Z'), "value": 37909, "basis": 33750 },
{ "date": new Date('2026-05-05T00:00:00.000Z'), "value": 37952, "basis": 33750 },
{ "date": new Date('2026-05-06T00:00:00.000Z'), "value": 37829, "basis": 33750 },
{ "date": new Date('2026-05-07T00:00:00.000Z'), "value": 37732, "basis": 33750 },
{ "date": new Date('2026-05-08T00:00:00.000Z'), "value": 37989, "basis": 33750 },
{ "date": new Date('2026-05-09T00:00:00.000Z'), "value": 37876, "basis": 33750 },
{ "date": new Date('2026-05-10T00:00:00.000Z'), "value": 38052, "basis": 33750 },
{ "date": new Date('2026-05-11T00:00:00.000Z'), "value": 38198, "basis": 33750 },
{ "date": new Date('2026-05-12T00:00:00.000Z'), "value": 38279, "basis": 33750 },
{ "date": new Date('2026-05-13T00:00:00.000Z'), "value": 38068, "basis": 33750 },
{ "date": new Date('2026-05-14T00:00:00.000Z'), "value": 38068, "basis": 33750 },
{ "date": new Date('2026-05-15T00:00:00.000Z'), "value": 38311, "basis": 33750 },
{ "date": new Date('2026-05-16T00:00:00.000Z'), "value": 38097, "basis": 33750 },
{ "date": new Date('2026-05-17T00:00:00.000Z'), "value": 38263, "basis": 33750 },
{ "date": new Date('2026-05-18T00:00:00.000Z'), "value": 38296, "basis": 33750 },
{ "date": new Date('2026-05-19T00:00:00.000Z'), "value": 38358, "basis": 33750 },
{ "date": new Date('2026-05-20T00:00:00.000Z'), "value": 38364, "basis": 33750 },
{ "date": new Date('2026-05-21T00:00:00.000Z'), "value": 38308, "basis": 33750 },
{ "date": new Date('2026-05-22T00:00:00.000Z'), "value": 38421, "basis": 33750 },
{ "date": new Date('2026-05-23T00:00:00.000Z'), "value": 38635, "basis": 33750 },
{ "date": new Date('2026-05-24T00:00:00.000Z'), "value": 39801, "basis": 35000 },
{ "date": new Date('2026-05-25T00:00:00.000Z'), "value": 39766, "basis": 35000 },
{ "date": new Date('2026-05-26T00:00:00.000Z'), "value": 39545, "basis": 35000 },
{ "date": new Date('2026-05-27T00:00:00.000Z'), "value": 39468, "basis": 35000 },
{ "date": new Date('2026-05-28T00:00:00.000Z'), "value": 39665, "basis": 35000 },
{ "date": new Date('2026-05-29T00:00:00.000Z'), "value": 39699, "basis": 35000 },
{ "date": new Date('2026-05-30T00:00:00.000Z'), "value": 39917, "basis": 35000 },
{ "date": new Date('2026-05-31T00:00:00.000Z'), "value": 40201, "basis": 35000 },
{ "date": new Date('2026-06-01T00:00:00.000Z'), "value": 40239, "basis": 35000 },
{ "date": new Date('2026-06-02T00:00:00.000Z'), "value": 40352, "basis": 35000 },
{ "date": new Date('2026-06-03T00:00:00.000Z'), "value": 40169, "basis": 35000 },
{ "date": new Date('2026-06-04T00:00:00.000Z'), "value": 40001, "basis": 35000 },
{ "date": new Date('2026-06-05T00:00:00.000Z'), "value": 40038, "basis": 35000 },
{ "date": new Date('2026-06-06T00:00:00.000Z'), "value": 40079, "basis": 35000 },
{ "date": new Date('2026-06-07T00:00:00.000Z'), "value": 40132, "basis": 35000 },
{ "date": new Date('2026-06-08T00:00:00.000Z'), "value": 40238, "basis": 35000 },
{ "date": new Date('2026-06-09T00:00:00.000Z'), "value": 40231, "basis": 35000 },
{ "date": new Date('2026-06-10T00:00:00.000Z'), "value": 40008, "basis": 35000 },
{ "date": new Date('2026-06-11T00:00:00.000Z'), "value": 40075, "basis": 35000 },
{ "date": new Date('2026-06-12T00:00:00.000Z'), "value": 40364, "basis": 35000 },
{ "date": new Date('2026-06-13T00:00:00.000Z'), "value": 40194, "basis": 35000 },
{ "date": new Date('2026-06-14T00:00:00.000Z'), "value": 40048, "basis": 35000 },
{ "date": new Date('2026-06-15T00:00:00.000Z'), "value": 40011, "basis": 35000 },
{ "date": new Date('2026-06-16T00:00:00.000Z'), "value": 40240, "basis": 35000 },
{ "date": new Date('2026-06-17T00:00:00.000Z'), "value": 40503, "basis": 35000 },
{ "date": new Date('2026-06-18T00:00:00.000Z'), "value": 40739, "basis": 35000 },
{ "date": new Date('2026-06-19T00:00:00.000Z'), "value": 40757, "basis": 35000 },
{ "date": new Date('2026-06-20T00:00:00.000Z'), "value": 40540, "basis": 35000 },
{ "date": new Date('2026-06-21T00:00:00.000Z'), "value": 40714, "basis": 35000 },
{ "date": new Date('2026-06-22T00:00:00.000Z'), "value": 40662, "basis": 35000 },
{ "date": new Date('2026-06-23T00:00:00.000Z'), "value": 42153, "basis": 36250 },
{ "date": new Date('2026-06-24T00:00:00.000Z'), "value": 42298, "basis": 36250 },
{ "date": new Date('2026-06-25T00:00:00.000Z'), "value": 42093, "basis": 36250 },
{ "date": new Date('2026-06-26T00:00:00.000Z'), "value": 42181, "basis": 36250 },
{ "date": new Date('2026-06-27T00:00:00.000Z'), "value": 42416, "basis": 36250 },
{ "date": new Date('2026-06-28T00:00:00.000Z'), "value": 42710, "basis": 36250 },
{ "date": new Date('2026-06-29T00:00:00.000Z'), "value": 42719, "basis": 36250 },
{ "date": new Date('2026-06-30T00:00:00.000Z'), "value": 42517, "basis": 36250 },
{ "date": new Date('2026-07-01T00:00:00.000Z'), "value": 42662, "basis": 36250 },
{ "date": new Date('2026-07-02T00:00:00.000Z'), "value": 42741, "basis": 36250 },
{ "date": new Date('2026-07-03T00:00:00.000Z'), "value": 42941, "basis": 36250 },
{ "date": new Date('2026-07-04T00:00:00.000Z'), "value": 42816, "basis": 36250 },
{ "date": new Date('2026-07-05T00:00:00.000Z'), "value": 42908, "basis": 36250 },
{ "date": new Date('2026-07-06T00:00:00.000Z'), "value": 42875, "basis": 36250 },
{ "date": new Date('2026-07-07T00:00:00.000Z'), "value": 42977, "basis": 36250 },
{ "date": new Date('2026-07-08T00:00:00.000Z'), "value": 43045, "basis": 36250 },
{ "date": new Date('2026-07-09T00:00:00.000Z'), "value": 43017, "basis": 36250 },
{ "date": new Date('2026-07-10T00:00:00.000Z'), "value": 42863, "basis": 36250 },
{ "date": new Date('2026-07-11T00:00:00.000Z'), "value": 42841, "basis": 36250 },
{ "date": new Date('2026-07-12T00:00:00.000Z'), "value": 42818, "basis": 36250 },
{ "date": new Date('2026-07-13T00:00:00.000Z'), "value": 42689, "basis": 36250 },
{ "date": new Date('2026-07-14T00:00:00.000Z'), "value": 42630, "basis": 36250 },
{ "date": new Date('2026-07-15T00:00:00.000Z'), "value": 42604, "basis": 36250 },
{ "date": new Date('2026-07-16T00:00:00.000Z'), "value": 42795, "basis": 36250 },
{ "date": new Date('2026-07-17T00:00:00.000Z'), "value": 42813, "basis": 36250 },
{ "date": new Date('2026-07-18T00:00:00.000Z'), "value": 42697, "basis": 36250 },
{ "date": new Date('2026-07-19T00:00:00.000Z'), "value": 42589, "basis": 36250 },
{ "date": new Date('2026-07-20T00:00:00.000Z'), "value": 42734, "basis": 36250 },
{ "date": new Date('2026-07-21T00:00:00.000Z'), "value": 42656, "basis": 36250 },
{ "date": new Date('2026-07-22T00:00:00.000Z'), "value": 42863, "basis": 36250 },
{ "date": new Date('2026-07-23T00:00:00.000Z'), "value": 44128, "basis": 37500 },
{ "date": new Date('2026-07-24T00:00:00.000Z'), "value": 43949, "basis": 37500 },
{ "date": new Date('2026-07-25T00:00:00.000Z'), "value": 44035, "basis": 37500 },
{ "date": new Date('2026-07-26T00:00:00.000Z'), "value": 44299, "basis": 37500 },
{ "date": new Date('2026-07-27T00:00:00.000Z'), "value": 44133, "basis": 37500 },
{ "date": new Date('2026-07-28T00:00:00.000Z'), "value": 44302, "basis": 37500 },
{ "date": new Date('2026-07-29T00:00:00.000Z'), "value": 44375, "basis": 37500 },
{ "date": new Date('2026-07-30T00:00:00.000Z'), "value": 44549, "basis": 37500 },
{ "date": new Date('2026-07-31T00:00:00.000Z'), "value": 44594, "basis": 37500 },
{ "date": new Date('2026-08-01T00:00:00.000Z'), "value": 44571, "basis": 37500 },
{ "date": new Date('2026-08-02T00:00:00.000Z'), "value": 44817, "basis": 37500 },
{ "date": new Date('2026-08-03T00:00:00.000Z'), "value": 44855, "basis": 37500 },
{ "date": new Date('2026-08-04T00:00:00.000Z'), "value": 44722, "basis": 37500 },
{ "date": new Date('2026-08-05T00:00:00.000Z'), "value": 44527, "basis": 37500 },
{ "date": new Date('2026-08-06T00:00:00.000Z'), "value": 44281, "basis": 37500 },
{ "date": new Date('2026-08-07T00:00:00.000Z'), "value": 44200, "basis": 37500 },
{ "date": new Date('2026-08-08T00:00:00.000Z'), "value": 44422, "basis": 37500 },
{ "date": new Date('2026-08-09T00:00:00.000Z'), "value": 44417, "basis": 37500 },
{ "date": new Date('2026-08-10T00:00:00.000Z'), "value": 44546, "basis": 37500 },
{ "date": new Date('2026-08-11T00:00:00.000Z'), "value": 44315, "basis": 37500 },
{ "date": new Date('2026-08-12T00:00:00.000Z'), "value": 44541, "basis": 37500 },
{ "date": new Date('2026-08-13T00:00:00.000Z'), "value": 44370, "basis": 37500 },
{ "date": new Date('2026-08-14T00:00:00.000Z'), "value": 44462, "basis": 37500 },
{ "date": new Date('2026-08-15T00:00:00.000Z'), "value": 44529, "basis": 37500 },
{ "date": new Date('2026-08-16T00:00:00.000Z'), "value": 44512, "basis": 37500 },
{ "date": new Date('2026-08-17T00:00:00.000Z'), "value": 44401, "basis": 37500 },
{ "date": new Date('2026-08-18T00:00:00.000Z'), "value": 44324, "basis": 37500 },
{ "date": new Date('2026-08-19T00:00:00.000Z'), "value": 44487, "basis": 37500 },
{ "date": new Date('2026-08-20T00:00:00.000Z'), "value": 44458, "basis": 37500 },
{ "date": new Date('2026-08-21T00:00:00.000Z'), "value": 44572, "basis": 37500 },
{ "date": new Date('2026-08-22T00:00:00.000Z'), "value": 45765, "basis": 38750 },
{ "date": new Date('2026-08-23T00:00:00.000Z'), "value": 45703, "basis": 38750 },
{ "date": new Date('2026-08-24T00:00:00.000Z'), "value": 45593, "basis": 38750 },
{ "date": new Date('2026-08-25T00:00:00.000Z'), "value": 45574, "basis": 38750 },
{ "date": new Date('2026-08-26T00:00:00.000Z'), "value": 45844, "basis": 38750 },
{ "date": new Date('2026-08-27T00:00:00.000Z'), "value": 46039, "basis": 38750 },
{ "date": new Date('2026-08-28T00:00:00.000Z'), "value": 46045, "basis": 38750 },
{ "date": new Date('2026-08-29T00:00:00.000Z'), "value": 46162, "basis": 38750 },
{ "date": new Date('2026-08-30T00:00:00.000Z'), "value": 46426, "basis": 38750 },
{ "date": new Date('2026-08-31T00:00:00.000Z'), "value": 46321, "basis": 38750 },
{ "date": new Date('2026-09-01T00:00:00.000Z'), "value": 46289, "basis": 38750 },
{ "date": new Date('2026-09-02T00:00:00.000Z'), "value": 46377, "basis": 38750 },
{ "date": new Date('2026-09-03T00:00:00.000Z'), "value": 46127, "basis": 38750 },
{ "date": new Date('2026-09-04T00:00:00.000Z'), "value": 46212, "basis": 38750 },
{ "date": new Date('2026-09-05T00:00:00.000Z'), "value": 45955, "basis": 38750 },
{ "date": new Date('2026-09-06T00:00:00.000Z'), "value": 45727, "basis": 38750 },
{ "date": new Date('2026-09-07T00:00:00.000Z'), "value": 45976, "basis": 38750 },
{ "date": new Date('2026-09-08T00:00:00.000Z'), "value": 46276, "basis": 38750 },
{ "date": new Date('2026-09-09T00:00:00.000Z'), "value": 46246, "basis": 38750 },
{ "date": new Date('2026-09-10T00:00:00.000Z'), "value": 46287, "basis": 38750 },
{ "date": new Date('2026-09-11T00:00:00.000Z'), "value": 46552, "basis": 38750 },
{ "date": new Date('2026-09-12T00:00:00.000Z'), "value": 46434, "basis": 38750 },
{ "date": new Date('2026-09-13T00:00:00.000Z'), "value": 46303, "basis": 38750 },
{ "date": new Date('2026-09-14T00:00:00.000Z'), "value": 46420, "basis": 38750 },
{ "date": new Date('2026-09-15T00:00:00.000Z'), "value": 46322, "basis": 38750 },
{ "date": new Date('2026-09-16T00:00:00.000Z'), "value": 46492, "basis": 38750 },
{ "date": new Date('2026-09-17T00:00:00.000Z'), "value": 46447, "basis": 38750 },
{ "date": new Date('2026-09-18T00:00:00.000Z'), "value": 46223, "basis": 38750 },
{ "date": new Date('2026-09-19T00:00:00.000Z'), "value": 46545, "basis": 38750 },
{ "date": new Date('2026-09-20T00:00:00.000Z'), "value": 46680, "basis": 38750 },
{ "date": new Date('2026-09-21T00:00:00.000Z'), "value": 48153, "basis": 40000 },
{ "date": new Date('2026-09-22T00:00:00.000Z'), "value": 48372, "basis": 40000 },
{ "date": new Date('2026-09-23T00:00:00.000Z'), "value": 48428, "basis": 40000 },
{ "date": new Date('2026-09-24T00:00:00.000Z'), "value": 48478, "basis": 40000 },
{ "date": new Date('2026-09-25T00:00:00.000Z'), "value": 48438, "basis": 40000 },
] },
];
export function Example() {
return (
);
}
```
### Data
```tsx
// One row per day: what the account is worth and what went into it.
const portfolio = [
{ date: new Date('2025-09-26'), value: 25084, basis: 25000 },
{ date: new Date('2025-10-26'), value: 26867, basis: 26250 }, // a deposit raises the basis
];
```
The chip is the gain over basis at the latest row, so deposits never read as returns. Drawdown is how far `value` sits below its highest point so far, zero at every new high; the pane reads the current drawdown and the worst in view. `drawdown` is exported for your own layouts.
### Hover
Hover a day to read its value in the headline; the drawdown pane reads the same day, and the basis draws as a stepped dashed line so each deposit shows as a step.
### Props
- `title` (`string`): Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
- `data` (`Row[]`): One row per x position. Omit when using ranges.
- `x` (`key of Row`): Text, number, or Date field for the x axis.
- `value` (`key of Row`): Numeric field holding the account value.
- `basis` (`key of Row`): Numeric field holding the cost basis, drawn as a stepped dashed line.
- `label` (`string`): Names the value series. Defaults to Value.
- `depth` (`boolean`): Lights the value path as a tube; the dashed basis stays flat.
- `drawdown` (`boolean`): Shade how far the value sits below its best in a linked pane. Defaults to true.
- `drawdownHeight` (`number`): Height of the drawdown pane in pixels. Defaults to 64.
- `header` (`boolean`): Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection.
- `aria-label` (`string`): Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
- `delta` (`number`): Fractional change for the chip: 0.082 shows +8.2%.
- `deltaTone` (`'default' | 'inverse' | 'neutral'`): Use inverse when a decrease is good.
- `range` (`string`): Static period label in the header.
- `ranges` (`{ id, label, data, delta?, headline? }[]`): Turns the period label into a select. Each range swaps the data.
- `valueFormat` (`Intl.NumberFormatOptions`): Formats the headline, tiles, and axis, e.g. currency.
- `legend` (`false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'`): False removes the legend without changing the data. How the legend under the plot lays out: value tiles (default), a compact inline key, list rows, tinted pills, or bars that also draw each value against the largest.
- `legendSwatch` (`'square' | 'dot' | 'line'`): The mark beside each legend label. Defaults to a rounded square.
- `height` (`number`): Plot height in pixels. Defaults to 240.
- `axis` (`'minimal' | 'dots' | 'inline' | 'ruler' | 'classic' | 'segmented' | { x, y }`): Axis preset. Minimal (default) labels only the x ends and has no grid. Set one per axis with `{ x, y }`; a segmented axis can take a `gradient` to read as a range.
- `hover` (`'pills' | 'tooltip' | 'strip' | 'headline'`): The one readout for the hovered point: pills on the axes (default), a tooltip with every series, a strip docked above the plot, or the headline and tiles alone.
- `hoverStyle` (`'soft' | 'solid' | 'accent'`): How the pills or tooltip look. Soft (default) is surface glass; accent tints it with the hovered series.
- `pillPosition` (`'auto' | 'mark' | 'axis'`): Where the value pill sits: above the hovered mark, or on the y axis. Auto picks mark when there are no y labels.
- `tooltipIndicator` (`'square' | 'dot' | 'line'`): Series marker on each tooltip row, with hover="tooltip". Square by default.
- `background` (`'dots' | 'grid' | 'lines' | 'none'`): Texture behind the marks. Dots by default, with a hover spotlight.
- `surface` (`'elevated' | 'outline' | 'ghost'`): Card treatment. Ghost removes the visual frame only; header and legend are independent controls.
- `palette` (`'iris' | 'cobalt' | 'emerald'`): Series colors. Iris by default; explicit series colors still win.
- `axisInset` (`number`): Padding between the plot edges and axis labels or pills.
- `loading` (`boolean`): Shows a neutral loading skeleton, not data.
- `loadingStyle` (`'shimmer' | 'draw' | 'breathe'`): Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion.
- `empty` (`'dots' | 'shape' | ReactElement | null`): What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero.
- `compare` (`boolean | 'headline' | 'badge'`): Drag across the plot to compare two points in time. True or headline reads the change in the headline; badge reads it in the card’s tab and leaves the headline at rest.
- `sync` (`string`): Link hover and pins with every card that uses the same name, matched by x value. A click pins them all, with a ghost pin on the others; Alt-click pins one card only.
- `numberStyle` (`'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble'`): How the headline animates when its value changes. Count (default) counts to the new value.
- `motion` (`'auto' | 'none'`): None turns off decorative motion; reduced motion does this automatically.
- `defaultRange` (`string`): Initial range id; defaults to the first supplied range.
- `locale` (`string`): Locale used for number formatting. Defaults to en-US.
- `formatValue` (`(value: number) => string`): Custom value text, taking precedence over valueFormat.
- `formatAxisValue` (`(value: number) => string`): Custom compact axis value text.
- `formatX` (`(value: string | number | Date) => string`): Custom x label text.
- `xType` (`'category' | 'number' | 'time'`): Override inferred x type. Use time for numeric Unix timestamps in milliseconds.
- `spotlight` (`boolean`): Highlight the inspected position in the plot background. Defaults to true.
- `badge` (`ReactNode`): Content in the tab above the card. A comparison badge can replace this while a comparison is active.
- `className` (`string`): Additional class on the card frame.
- `style` (`CSSProperties | ChartStyle`): Inline styles and scoped --lilt-* chart variables.
- `pillValue` (`'series' | 'stack'`): Read an individual series value (default) or its stacked height. Has no effect when the card has no stacked series.
- `decimate` (`boolean`): Defaults to true. Line and Area marks retain at most four observations per pixel column. Other marks draw every row; inspection and summaries always read the full data.
- `bleed` (`boolean`): Let marks reach the card edges with a soft fade.
- `headline` (`number`): Override the resting headline; an active range headline takes precedence.