ChartContainer
import { ChartContainer } from '@wick-charts/react'; <ChartContainer theme={catppuccin.theme}> <LineSeries data={data} /></ChartContainer>Top-level React wrapper that creates a ChartInstance and provides it to children via context. Owns the DOM container and canvas lifecycle; renders children as an overlay layer.
Detects <Title>, <InfoBar>, and <Legend> children and positions them as:
- Title + InfoBar — absolutely-positioned *overlays* stacked at the top of the canvas
block, so the canvas (and therefore the grid) fills the full container height. The stacked height is measured and fed back into chart.setPadding({ top }) so series data stays below them.
- Legend — flex sibling at the bottom (or right, when position="right"), so its height is
reserved by browser layout.
The root component every chart starts with. Provides theme, axis configuration, padding, and the canvas; collects series and overlays from its children. Use viewport={{ maxVisibleBars, initialRange }} to size the streaming window and apply an initial zoom *before* the first paint (same shape as the imperative chart.setVisibleRange).
Props
Series components and UI overlays (Tooltip, TimeAxis, etc.) rendered inside the chart.
Visual theme. Live — changing this at runtime updates all themed elements.
Grouped axis configuration (Y/X visibility, bounds, sizing). Live.
Named secondary Y scales, keyed by id — a series opts in with its scale prop and autoscales on its own, sharing the time axis. Same fields as axis.y; position defaults to the side opposite the default axis. One axis column fits on each side — render it with <YAxis scale="id" />. Live.
{
top?: number;
bottom?: number;
right?: number | {
intervals: number
};
left?: number | {
intervals: number
};
}Viewport padding around the plot area. Live — a later change re-applies via chart.setPadding. Set every side to 0 for an edge-to-edge sparkline.
{
maxVisibleBars?: number;
initialRange?: VisibleRangeSpec;
}Viewport-level streaming behavior. Captured at mount only — changing this prop after the chart is created is ignored.
Controlled visible range. Same shape as the imperative chart.setVisibleRange — a bar count, an explicit {from, to} window, or {from, bars}. Every reference/value change applies via chart.setVisibleRange, so pair it with onVisibleRangeChange for a two-way binding; a same-value literal (compared structurally) is a no-op, so an inline object from a parent re-render doesn't re-apply.
For a one-shot initial window that isn't re-applied on every prop change, use viewport.initialRange instead.
Show the chart background gradient. Live. Defaults to false.
Enable zoom, pan, and crosshair interactions. Defaults to true.
Mount-only — core has no setInteractive, so changing this prop after mount is ignored.
Background grid configuration. Live. Default: { visible: true }.
boolean | {
top?: number;
overlap?: number;
right?: number;
left?: number
}Soft fade-out at the top of the plot area, so series content dissolves under a floating <Title> / <InfoBar> instead of colliding with it — a Y-axis spring lag, a streaming spike, or a warm-up burst glides into transparency. The mask erases canvas alpha rather than painting a cover color, so it stays correct over a background gradient. Live.
Two directions, independently controlled:
X (under the axis) — panning content slides under the Y-axis column and dissolves instead of hard-clipping at the pane edge. On by default as a 60px ramp that finishes just inside the axis column, before the label glyphs — on whichever side axis.y.position puts it (a left-axis ramp ends at the pane edge instead). The axis side's key ({ right } by default, { left } for a left axis) overrides the total ramp width in CSS px (0 disables); the other key adds a plain zone at the opposite pane edge (default off). A chart with only pie / heatmap series has no axis column, so both keys add plain zones there.
Top (under the header) — opt-in. true enables the auto zone (measured header + 24px run-out, half the header fold-in released so data rides up into the zone at rest), { top } sets the zone height explicitly, and { overlap } tunes how many px of the fold-in to release (0 keeps the strict fold-in). Off unless one of those is set.
false — every mask off, strict edges everywhere.
How <Title> and <InfoBar> are positioned relative to the canvas. Live.
- 'overlay' (default): absolute overlays on top of the canvas — the grid
and Y-axis labels render full-height behind the header strip.
- 'inline': flex siblings above the canvas — the canvas (and grid) are
shifted down by the measured header height, so nothing renders behind the title. The chart background still spans the full container.
Animation control. true / omitted uses built-in defaults; false disables every category. Per-series options on <LineSeries> / <CandlestickSeries> / <BarSeries> override these chart-level defaults unless the category here is explicitly false.
Init-only, but diffed by value, not reference. A same-value inline object literal is a no-op — only a genuine change to the resolved config recreates the underlying ChartInstance (and its canvas), since the animation engine doesn't support live reconfiguration yet. Still worth a stable reference (useMemo(() => ({...}), [deps])) to avoid the per-render deep-equal check, but forgetting it no longer tears the chart down. In dev mode the container emits a console warning if it detects >3 *genuine* recreates/s.
Runtime performance instrumentation. Off by default — pass a config factory, not a plain object (that pulls the perf module into your bundle only when you actually use it):
- perfHud() — attach a PerfMonitor and render a visible HUD overlay on this chart.
- perfHud({ windowMs, maxSamples, ... }) — same, with monitor options.
- perfHud(existingMonitor) — attach a visible HUD to an already-created monitor.
- a raw PerfMonitor instance — instrumentation without the HUD.
Only read at mount; changing this prop after the chart is created is ignored.
Fired after the user releases a pan/zoom gesture that pulled the viewport past a data edge by more than ~10% of the visible range. Hosts typically respond by prefetching more history.
For threshold-based prefetch (load *before* the user fully overshoots), use <EdgeLoader> instead — that component subscribes to viewportChange and arms when the visible range nears the data edge.
Captured at mount only; changing the prop identity later is ignored.
Fired on a click (or tap) on the chart canvas that isn't the tail end of a pan drag. info.spatialHit resolves a pie/heatmap/custom-spatial series directly under the pointer; for a time-series series, resolve the point yourself from info.time (chart.getDataAtTime / buildHoverSnapshots). Live — the latest callback is always used.
Fired on a double-click on the chart canvas. The chart also responds by calling fitContent(). Live — the latest callback is always used.
Fired when the spatially-hovered series/index changes (pie, heatmap, or a custom spatial kind) — null when the pointer leaves every hit area. Live — the latest callback is always used.
Fired once the underlying ChartInstance is constructed — on mount, and again if the chart is ever rebuilt (a genuine animations value change). Use this to reach for imperative APIs the declarative props don't cover yet. Live — the latest callback is always used for the next rebuild.
Fired whenever the committed visible range changes — pan, zoom, fitContent(), a data update that shifts the tail-scroll window, or a visibleRange prop change. Live — the latest callback is always used.
Fired on every crosshair move, with null when the pointer leaves the chart. Live — the latest callback is always used.
Inline style for the chart's outer wrapper element. Live.
Extra class for the chart's outer wrapper element. Live.
Render prop
// <ChartContainer> accepts arbitrary children.