Install the framework adapter, core grammar, Octane peer, and only the granular data and scale modules used by the chart:
pnpm add @tanstack/charts @tanstack/octane-charts octane d3-scale
pnpm add -D @types/d3-scaleThe shared Scales and D3 page explains the injected scale and algorithm boundary.
Definitions are framework-independent and can be shared with any adapter:
import { scaleBand, scaleLinear } from 'd3-scale'
import { barY, defineChart } from '@tanstack/charts'
import { Chart } from '@tanstack/octane-charts'
const revenue = [
{ month: 'Jan', value: 42 },
{ month: 'Feb', value: 58 },
{ month: 'Mar', value: 76 },
{ month: 'Apr', value: 64 },
]
const revenueChart = defineChart({
marks: [
barY(revenue, {
x: 'month',
y: 'value',
}),
],
x: {
scale: () => scaleBand().padding(0.18),
},
y: {
scale: scaleLinear,
nice: true,
label: 'Revenue',
grid: true,
},
tooltip: true,
})
export function RevenueChart() {
return (
<Chart definition={revenueChart} height={320} ariaLabel="Monthly revenue" />
)
}The definition infers the row, scale, and callback types. Normal TSRX authoring does not need Chart generics or casts.
Use height for a fixed-height responsive chart:
<Chart definition={revenueChart} height={320} ariaLabel="Monthly revenue" />Use aspectRatio when height should follow width:
<Chart
definition={revenueChart}
aspectRatio={16 / 9}
initialWidth={720}
ariaLabel="Monthly revenue"
/>The server scene uses initialWidth, then the shared host measures the actual container after hydration. See Octane adapter.
import { useMemo } from 'octane'
interface RevenueInput {
rows: readonly { month: string; value: number }[]
accent: string
}
export function LiveRevenue({ rows, accent }: RevenueInput) {
const definition = useMemo(() => {
return defineChart({
marks: [
barY(rows, {
x: 'month',
y: 'value',
fill: accent,
}),
],
x: {
scale: () => scaleBand().padding(0.18),
},
y: {
scale: scaleLinear,
nice: true,
},
animate: true,
tooltip: true,
})
})
return (
<Chart
definition={definition}
height={320}
ariaLabel="Live monthly revenue"
/>
)
}Octane tracks the values read by useMemo. Definition identity tells the chart host when captured values changed. See Chart Definition API.
<Chart
definition={revenueChart}
height={320}
ariaLabel="Monthly revenue"
onFocusChange={(point) => {
if (point) {
console.log(point.datum.month, point.yValue)
}
}}
onSelect={(point) => {
if (point) openMonth(point.datum.month)
}}
/>Grouped focus, tooltip formatting, keyboard behavior, and application-owned interaction are documented in Focus and interaction.
This calendar heatmap uses typed cells and responsive guide layout through the same Octane adapter:
Continue with the Octane adapter for lifecycle and SSR, the Chart reference for every prop, or the core API reference.