Production

Responsive sizing

Omit width: GGPlot observes its container. Positive-width block, no chart CSS. Omitted height: 400px default. Collapsed parent, hidden tab, or zero-width track → not-ready until ResizeObserver reports positive width. Do not paper over that with a fake fixed width. Troubleshooting.

SSR uses an 832×400 deterministic fallback and stays not-ready in HTML until hydration measures the real container. Reserve layout space to avoid CLS.

Rendering

Renderer follows mark density and interaction needs. Axes, legends, labels, and a11y chrome stay semantic regardless of SVG vs canvas.

SVG: DOM marks. Canvas: dense strata. Auto: switches above the published threshold and emits canvas-auto. 2.5k-point scatter: canvas marks, SVG axes/legend.

Inspection and selection use the model-owned candidate store, not DOM hit tests. Stable keys keep identity across SVG/canvas; renderer indices never appear in public callbacks. Measure with repo fixtures before forcing canvas globally.

Server and export

Three paths, one PortableSpec: Svelte SSR, pure renderToSVGString, CLI.

import { renderToSVGString } from "@ggsvelte/core";

const svg = renderToSVGString(spec, { width: 640, height: 400 });
ggsvelte-render spec.json > chart.svg

SVG on stdout; JSON Lines diagnostics on stderr. CLI reference.

Compatibility

Every release is tested as an installed package: clean install, strict type-check, client build, server render, pure Node render, and the ggsvelte-render CLI.

  • Node.js >=22 (22 and 24 in CI; 26 nightly)
  • Svelte ^5.33.1 (tested floor 5.33.1, current 5.56.5)
  • npm bundled with Node, pnpm 11.13.0, Bun 1.3.14
  • Chromium, Firefox, and WebKit (Playwright 1.61.1)
  • Ubuntu and Windows in CI; macOS nightly

Exact machine-checked rows live in support-matrix.json. Bun is the contributor toolchain only; consumers can use any installer above.