Charts
Overview
Pure SVG charts with no extra dependency. Every chart reads colors from the theme tokens, so light and dark mode work out of the box.
The family: LineChart, AreaChart, BarChart, BarSegment, Histogram, RangeBarChart, CandlestickChart, PieChart, DonutChart, RadarChart, ScatterChart and Sparkline. Shared pieces are useChart, ChartLegend, CartesianGrid and ChartAxis.
Import
tsx
import { Chart } from "@indoku/ui"// <Chart.LineChart />, <Chart.BarChart />, Chart.useChart(), ...Anatomy
Chart.LineChart | AreaChart | BarChart | ... CartesianGrid (grid lines) ChartAxis (bottom / left / right) ChartLegend (interactive, driven by useChart)Examples
Installation
Charts ship inside @indoku/ui. Only React and Emotion are required.
tsx
function ChartInstall() { const sales = [120, 180, 150, 220, 260, 240] return <Chart.LineChart categories={["Jan", "Feb", "Mar", "Apr", "May", "Jun"]} series={[{ name: "Sales", values: sales }]} />}useChart
Shared tokens, number formatting and legend highlight.
tsx
function ChartUseChart() { const series = [ { name: "Revenue", values: [120, 180, 150, 220, 260, 240] }, { name: "Cost", color: "red", values: [80, 90, 100, 110, 120, 130] }, ] const chart = Chart.useChart({ series, format: (v) => `$${v}k` }) return ( <div> <Chart.LineChart categories={["Jan", "Feb", "Mar", "Apr", "May", "Jun"]} series={series} highlight={chart.active} yTickFormat={chart.format} /> <Chart.ChartLegend items={series.map((s, i) => ({ name: s.name, color: chart.colors[i] }))} chart={chart} /> </div> )}Sorting
sortChartData and compactFormat helpers.
tsx
function ChartSorted() { const data = [ { name: "Organic", value: 45 }, { name: "Direct", value: 25 }, { name: "Referral", value: 18 }, { name: "Social", value: 12 }, ] const sorted = Chart.sortChartData(data, (d) => d.value, "desc") return <Chart.BarChart categories={sorted.map((d) => d.name)} series={[{ name: "Visits", values: sorted.map((d) => d.value) }]} yTickFormat={Chart.compactFormat} />}Bar: grouped
tsx
function BarGrouped() { return ( <Chart.BarChart legend categories={["Q1", "Q2", "Q3", "Q4"]} series={[ { name: "2025", values: [40, 65, 52, 90] }, { name: "2026", values: [55, 70, 80, 110] }, ]} /> )}Bar: stacked
tsx
function BarStacked() { return ( <Chart.BarChart mode="stacked" legend categories={["Mon", "Tue", "Wed", "Thu", "Fri"]} series={[ { name: "Web", values: [30, 40, 35, 50, 45] }, { name: "iOS", values: [20, 25, 30, 22, 28] }, { name: "Android", values: [15, 18, 20, 25, 30] }, ]} /> )}Bar: percent
tsx
function BarPercent() { return ( <Chart.BarChart mode="percent" legend categories={["A", "B", "C", "D"]} series={[ { name: "Passed", values: [60, 45, 80, 70] }, { name: "Failed", values: [40, 55, 20, 30] }, ]} /> )}Bar segment
One segmented bar for composition.
tsx
function BarSegmentDemo() { return ( <Chart.BarSegment data={[ { name: "Design", value: 420 }, { name: "Engineering", value: 860 }, { name: "Marketing", value: 310 }, ]} /> )}Histogram
tsx
function HistogramDemo() { const values = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9] return <Chart.Histogram values={values} bins={5} />}Range bar
tsx
function RangeBarDemo() { return ( <Chart.RangeBarChart data={[ { label: "Mon", min: 18, max: 27 }, { label: "Tue", min: 20, max: 30 }, { label: "Wed", min: 17, max: 25 }, { label: "Thu", min: 21, max: 33 }, ]} /> )}Candlestick
tsx
function CandlestickDemo() { return ( <Chart.CandlestickChart data={[ { label: "1", open: 100, high: 112, low: 96, close: 108 }, { label: "2", open: 108, high: 115, low: 104, close: 106 }, { label: "3", open: 106, high: 110, low: 98, close: 101 }, { label: "4", open: 101, high: 120, low: 99, close: 118 }, { label: "5", open: 118, high: 124, low: 112, close: 114 }, ]} /> )}Line: dashed series
tsx
function LineDashed() { return ( <Chart.LineChart legend categories={["Jan", "Feb", "Mar", "Apr", "May"]} series={[ { name: "Actual", values: [10, 25, 18, 32, 40] }, { name: "Forecast", color: "orange", dashed: true, values: [12, 22, 24, 30, 38] }, ]} /> )}Line: gradient area
tsx
function LineGradient() { return <Chart.LineChart area gradient showDots categories={["Jan", "Feb", "Mar", "Apr", "May", "Jun"]} series={[{ name: "Users", values: [30, 45, 38, 62, 70, 91] }]} />}Line: biaxial
Per-series axis with rightTickFormat.
tsx
function LineBiaxial() { return ( <Chart.LineChart legend categories={["Jan", "Feb", "Mar", "Apr", "May"]} rightTickFormat={(v) => `${v}%`} series={[ { name: "Revenue", values: [120, 150, 170, 160, 210] }, { name: "Conversion", color: "green", axis: "right", values: [2.1, 2.4, 3.0, 2.8, 3.6] }, ]} /> )}Line: connect nulls + series labels
tsx
function LineConnectNulls() { return <Chart.LineChart connectNulls seriesLabels categories={["Jan", "Feb", "Mar", "Apr", "May", "Jun"]} series={[{ name: "Signups", values: [10, 20, null, 35, null, 50] }]} />}Area: gradient fill
tsx
function AreaGradient() { return <Chart.AreaChart categories={["Jan", "Feb", "Mar", "Apr", "May", "Jun"]} series={[{ name: "Traffic", values: [20, 35, 30, 50, 65, 60] }]} />}Area: percent
tsx
function AreaPercent() { return ( <Chart.AreaChart mode="percent" legend categories={["Jan", "Feb", "Mar", "Apr", "May"]} series={[ { name: "Free", values: [50, 45, 40, 35, 30] }, { name: "Pro", values: [30, 35, 40, 45, 50] }, { name: "Team", values: [20, 20, 20, 20, 20] }, ]} /> )}Area: reference area and dots
tsx
function AreaReference() { return ( <Chart.AreaChart showDots referenceArea={{ from: 2, to: 3, label: "Promo" }} categories={["Jan", "Feb", "Mar", "Apr", "May", "Jun"]} series={[{ name: "Orders", values: [12, 18, 40, 52, 30, 28] }]} /> )}Pie: padding and detached segment
tsx
function PieDemo() { return ( <Chart.PieChart legend padAngle={2} detached={[0]} data={[ { name: "Organic", value: 45 }, { name: "Direct", value: 25 }, { name: "Referral", value: 18 }, { name: "Social", value: 12 }, ]} /> )}Donut: radial text
tsx
function DonutDemo() { return ( <Chart.DonutChart legend radialText={{ label: "100", sublabel: "visits" }} data={[ { name: "Organic", value: 45 }, { name: "Direct", value: 25 }, { name: "Referral", value: 18 }, { name: "Social", value: 12 }, ]} /> )}Radar: filled grid
tsx
function RadarDemo() { return ( <Chart.RadarChart legend grid="filled" axes={["Speed", "Power", "Range", "Armor", "Stealth"]} series={[ { name: "Alpha", values: [8, 6, 7, 5, 9] }, { name: "Beta", color: "orange", values: [5, 9, 6, 8, 4] }, ]} /> )}Radar: circle grid
tsx
function RadarCircle() { return <Chart.RadarChart grid="circle" axes={["HTML", "CSS", "JS", "TS", "Node"]} series={[{ name: "Skills", values: [9, 8, 9, 7, 6] }]} />}Scatter: groups and trend lines
tsx
function ScatterDemo() { return ( <Chart.ScatterChart trendLine legend series={[ { name: "Group A", points: [{ x: 1, y: 2 }, { x: 2, y: 3.5 }, { x: 3, y: 3 }, { x: 4, y: 5.2 }, { x: 5, y: 6 }] }, { name: "Group B", color: "orange", points: [{ x: 1, y: 5 }, { x: 2, y: 4.2 }, { x: 3, y: 3.8 }, { x: 4, y: 2.5 }, { x: 5, y: 2 }] }, ]} /> )}Scatter: connected dots
tsx
function ScatterConnected() { return <Chart.ScatterChart connect dotSize={5} series={[{ name: "Path", points: [{ x: 0, y: 0 }, { x: 2, y: 3 }, { x: 4, y: 1 }, { x: 6, y: 5 }, { x: 8, y: 4 }] }]} />}Sparkline
Plain, trend-colored with area, and interactive tooltip.
tsx
function SparklineDemo() { return ( <div style={{ display: "flex", gap: 24, alignItems: "center" }}> <Chart.Sparkline values={[3, 5, 4, 7, 6, 9, 12]} /> <Chart.Sparkline values={[12, 10, 11, 8, 7, 5, 4]} color="trend" area /> <Chart.Sparkline values={[4, 8, 6, 10, 9, 14]} interactive width={160} height={40} /> </div> )}Grid, axis and reference lines
tsx
function GridAxisDemo() { return ( <Chart.LineChart showGrid categories={["Mon", "Tue", "Wed", "Thu", "Fri"]} xTickFormat={(label) => label.slice(0, 1)} yTickFormat={(v) => `${v} ms`} referenceLines={[{ value: 60, label: "SLA", color: "red.500", dashed: true }]} series={[{ name: "Latency", values: [42, 55, 48, 63, 51] }]} /> )}Props
ChartLegend
| Prop | Type | Default | Description |
|---|---|---|---|
items* | { name: string; color: string }[] | – | |
chart* | ChartApi | – |
CartesianGrid
| Prop | Type | Default | Description |
|---|---|---|---|
x0* | number | – | |
x1* | number | – | |
y0* | number | – | |
y1* | number | – | |
horizontal | number[] | – | Posisi y (px) tiap garis horizontal. |
vertical | number[] | – | Posisi x (px) tiap garis vertikal. |
ChartAxis
| Prop | Type | Default | Description |
|---|---|---|---|
orientation* | "bottom" | "left" | "right" | – | |
at* | number | – | Posisi garis sumbu (px): y untuk bottom, x untuk left/right. |
ticks* | { pos: number; label: string }[] | – |
LineChart
| Prop | Type | Default | Description |
|---|---|---|---|
series* | ChartSeries[] | – | |
categories | string[] | – | Label for each data point (x axis), used for the point's aria-label. |
area | boolean | false | Fill the area under the line (area chart). |
gradient | boolean | – | Isi area pakai gradient (memudar ke bawah). |
showDots | boolean | – | |
dashed | boolean | – | Semua garis putus-putus (atau per series lewat series[i].dashed). |
connectNulls | boolean | – | Sambung garis melewati nilai null. |
seriesLabels | boolean | – | Tampilkan nama series di ujung garis. |
rightTickFormat | ChartFormat | – |
AreaChart
| Prop | Type | Default | Description |
|---|---|---|---|
series* | ChartSeries[] | – | |
categories | string[] | – | |
mode | "overlap" | "stacked" | "percent" | – | "overlap" (default), "stacked" (ditumpuk) atau "percent" (ditumpuk, 0-100%). |
gradient | boolean | true | Isi pakai gradient. |
showDots | boolean | – | Tanda titik di tiap data. |
referenceArea | { from: number; to: number; label?: string } | – | Blok warna di antara dua index kategori. |
BarChart
| Prop | Type | Default | Description |
|---|---|---|---|
series* | ChartSeries[] | – | |
categories | string[] | – | |
mode | "grouped" | "stacked" | "percent" | – | "grouped" (default), "stacked" atau "percent" (ditumpuk, 0-100%). |
gap | number | 0.3 | Gap between category groups, 0–1 (share of the slot width). |
joined | boolean | – | Hilangkan jarak antar bar (histogram). |
Histogram
| Prop | Type | Default | Description |
|---|---|---|---|
values* | number[] | – | |
bins | number | akar jumlah data (aturan Sturges sederhana) | Jumlah bin. |
color | string | – | |
name | string | – |
RangeBarChart
| Prop | Type | Default | Description |
|---|---|---|---|
data* | RangeDatum[] | – | |
color | string | – | |
gap | number | – |
CandlestickChart
| Prop | Type | Default | Description |
|---|---|---|---|
data* | CandleDatum[] | – | |
upColor | string | – | Warna naik / turun (token warna). |
downColor | string | – |
BarSegment
| Prop | Type | Default | Description |
|---|---|---|---|
data* | BarSegmentDatum[] | – | |
barHeight | number | 12 | Tinggi bar (px). |
showLegend | boolean | true | Tampilkan legend dengan nilai & persentase. |
format | ChartFormat | – |
PieChart
| Prop | Type | Default | Description |
|---|---|---|---|
data* | PieDatum[] | – | |
size | number | – | |
innerRadiusRatio | number | 0 | 0 = full pie, e.g. 0.6 = donut with a 60% radius hole. |
padAngle | number | 0 | Celah antar segmen (derajat). |
detached | number[] | – | Index segmen yang digeser keluar. |
detachDistance | number | 8 | Jarak geser segmen (px). |
radialText | { label: string; sublabel?: string } | – | Teks di tengah (donut): label besar + sublabel kecil. |
legend | boolean | – | Legend interaktif. |
RadialText
| Prop | Type | Default | Description |
|---|---|---|---|
x* | number | – | |
y* | number | – | |
label* | string | – | |
sublabel | string | – |
RadarChart
| Prop | Type | Default | Description |
|---|---|---|---|
axes* | string[] | – | Nama tiap sumbu (minimal 3). |
series* | ChartSeries[] | – | |
size | number | – | |
levels | number | 4 | Jumlah lingkaran/poligon grid. |
grid | "polygon" | "circle" | "filled" | – | Bentuk grid: "polygon" (default), "circle" atau "filled" (selang-seling terisi). |
pointLabels | boolean | true | Label di tiap sumbu. |
max | number | nilai terbesar data | Nilai maksimum sumbu. |
legend | boolean | – | |
highlight | number | null | – |
ScatterChart
| Prop | Type | Default | Description |
|---|---|---|---|
series* | ScatterSeries[] | – | Satu atau lebih grup data. |
trendLine | boolean | – | Garis tren regresi linear per grup. |
connect | boolean | – | Sambungkan titik berurutan dengan garis. |
dotSize | number | 4 | Radius titik. |
referenceLines | ReferenceLineSpec[] | – |
Sparkline
| Prop | Type | Default | Description |
|---|---|---|---|
values* | number[] | – | |
width | number | – | |
height | number | – | |
color | string | – | Token warna, atau "trend" (hijau kalau naik, merah kalau turun). |
area | boolean | – | Isi area di bawah garis. |
interactive | boolean | false | Tampilkan nilai titik yang di-hover (tooltip). |
format | ChartFormat | – |
* required. Style props and HTML attributes are accepted as well.
Accessibility
- Charts are decorative SVG; pair them with a table or text summary for screen readers.
- Legend items are focusable and highlight their series on focus.
Notes
nullvalues create gaps unlessconnectNullsis set.- Series colors accept a palette name (
blue) or a full token (blue.500).
Created by @indokudev