Components
Chart
A self-built canvas time-series chart engine sharing the chart-kit math layer — automatic canvas theming, responsive width, interactive legend and hover tooltip
A canvas time-series chart for large datasets — for categorical or small data see Donut, Radar and Sparkline.
Installation
Chart depends on the useChartPalette hook and the chart-kit / chart-paint utilities — litefy add chart installs them automatically:
- $npx litefy@latest add use-chart-palette
- $pnpm dlx litefy@latest add use-chart-palette
- $yarn dlx litefy@latest add use-chart-palette
- $bun --bun litefy@latest add use-chart-palette
useChartPalette can also be used standalone for custom visualizations — call useChartPalette({ mode: "wheel" | "mono" }) to get 8 theme-synced colors. See use-chart-palette for details.
Usage
Line Chart
A basic line chart on a time axis.
"use client";
import { Chart } from "@/ui";
import type { ChartSeriesConfig } from "@/ui";
function seeded(seed: number) {
let state = seed;
return () => {
state = (state * 1664525 + 1013904223) % 4294967296;
return state / 4294967296;
};
}
const random = seeded(42);
const day = 86400;
const points = 30;
const now = Math.floor(Date.now() / 1000);
const x = Array.from({ length: points }, (_, i) => now - (points - 1 - i) * day);
const visits = x.map((_, i) => Math.round(700 + Math.sin(i / 4) * 150 + random() * 80));
const orders = x.map((_, i) => Math.round(450 + Math.cos(i / 5) * 80 + random() * 40));
const revenue = x.map((_, i) => Math.round(1000 + Math.sin(i / 6) * 250 + random() * 120));
const signups = x.map((_, i) => Math.round(200 + Math.sin(i / 3) * 50 + random() * 30));
const data: [number[], ...number[][]] = [x, visits, orders, revenue, signups];
const series: ChartSeriesConfig[] = [
{ label: "Visits" },
{ label: "Orders" },
{ label: "Revenue", width: 2 },
{ label: "Signups" },
];
export default function ChartLineDemo() {
return (
<div className="w-full max-w-2xl">
<Chart data={data} series={series} height={260} />
</div>
);
}
Area Chart
An area series — set fill: true or type: "area".
"use client";
import { Chart } from "@/ui";
import type { ChartSeriesConfig } from "@/ui";
function seeded(seed: number) {
let state = seed;
return () => {
state = (state * 1664525 + 1013904223) % 4294967296;
return state / 4294967296;
};
}
const random = seeded(7);
const day = 86400;
const points = 20;
const now = Math.floor(Date.now() / 1000);
const x = Array.from({ length: points }, (_, i) => now - (points - 1 - i) * day);
const high = x.map((_, i) => Math.round(8 + Math.sin(i / 3) * 6 + random() * 3));
const avg = x.map((_, i) => Math.round(1 + Math.sin(i / 5) * 4 + random() * 2));
const low = x.map((_, i) => Math.round(-6 + Math.sin(i / 4) * 5 + random() * 3));
const data: [number[], ...number[][]] = [x, high, avg, low];
const series: ChartSeriesConfig[] = [
{ label: "High", fill: true },
{ label: "Avg" },
{ label: "Low", fill: true },
];
export default function ChartAreaDemo() {
return (
<div className="w-full max-w-2xl">
<Chart data={data} series={series} height={220} />
</div>
);
}
Bar Chart
Grouped bars via type: "bar"; pair with time={false} for a numeric x axis.
"use client";
import { Chart } from "@/ui";
import { useChartPalette } from "@/ui";
import type { ChartSeriesConfig } from "@/ui";
const x = Array.from({ length: 12 }, (_, i) => i + 1);
const returning = [420, 480, 510, 640, 720, 810, 940, 880, 1020, 1150, 1240, 1380];
const fresh = [180, 220, 260, 310, 380, 420, 460, 440, 520, 590, 660, 740];
const data: [number[], ...number[][]] = [x, returning, fresh];
export default function ChartBarsDemo() {
const palette = useChartPalette({ mode: "mono" });
const series: ChartSeriesConfig[] = [
{
label: "Returning",
type: "bar",
stroke: palette[0],
fill: palette[0],
},
{
label: "New",
type: "bar",
stroke: palette[1],
fill: palette[1],
value: (v) => `${v} users`,
},
];
return (
<div className="w-full max-w-2xl">
<Chart data={data} series={series} height={220} time={false} />
</div>
);
}
API Reference
ChartProps
| Prop | Type | Default | Description |
|---|---|---|---|
| data | ChartData ([number[], ...number[][]]) | - | Aligned chart data, first array is x values |
| series | ChartSeriesConfig[] | - | Series configs, one per y array in data |
| height | number | 240 | Chart height in pixels; width always adapts to the container |
| time | boolean | true | Whether the x axis is a time scale; when false it is treated as plain numbers |
| className | ClassNameValue | - | Extra classes appended to the root element |
| onReady | () => void | - | Called once after the first render |
ChartSeriesConfig
| Prop | Type | Default | Description |
|---|---|---|---|
| label | string | - | Series name, shown in the legend and tooltip |
| type | "line" | "area" | "bar" | "line" | How the series is drawn |
| stroke | string | Auto from palette | Line color, any valid CSS color |
| width | number | 1.5 | Line width in pixels (line / area only) |
| fill | string | boolean | - | Area fill; true uses the line color at 18% opacity, a string is used as a custom fill color |
| value | (v: number) => string | - | Value formatter used in the tooltip |
| show | boolean | true | Whether the series is initially visible |