DuckVizBeta
Packages

@duckviz/widgets

Chart component registry with 80+ D3 chart types, alias validator, and an error boundary.

@duckviz/widgets contains every D3 chart used by DuckViz (80+ types across 15 families), plus the alias validator, row-cap helpers, and <ChartErrorBoundary> used by @duckviz/dashboard and @duckviz/explorer. A standalone <WidgetRenderer> runs a SQL query and renders the result.

Installation

npm install @duckviz/widgets @duckviz/db
npm install react react-dom d3

Quick start

import { WidgetRenderer } from "@duckviz/widgets";
import { DuckvizDBProvider } from "@duckviz/db";

function App() {
  return (
    <DuckvizDBProvider persistence>
      <WidgetRenderer
        widget={{
          type: "bar",
          title: "Top Categories",
          description: "Revenue by category",
          duckdbQuery: "SELECT category, SUM(amount) AS value FROM t_sales GROUP BY category ORDER BY value DESC LIMIT 10",
        }}
        height={300}
      />
    </DuckvizDBProvider>
  );
}

<WidgetRenderer> props

Prop

Type

The widget object shape:

interface RecommendedWidget {
  type: string;        // Chart type (e.g. "bar", "scatter", "heatmap")
  title: string;
  description: string;
  duckdbQuery: string; // DuckDB SQL query with standardized column aliases
  config?: Record<string, unknown>;
}

Chart registry API

Look up chart components programmatically:

import { getChartComponent, hasChartComponent } from "@duckviz/widgets";

// Check if a chart type exists
hasChartComponent("bar");      // true
hasChartComponent("unknown");  // false

// Get the React component for a chart type
const BarChart = getChartComponent("bar");
// Returns null if the type doesn't exist

Column alias contract

Each chart type expects specific column names in the SQL output. This standardization lets pre-built chart components render any dataset without custom mapping.

Common alias patterns:

Chart typeExpected columnsExample SQL
barcategory, valueSELECT dept AS category, COUNT(*) AS value FROM ...
linecategory, valueSELECT month AS category, total AS value FROM ...
scatterx, ySELECT age AS x, salary AS y FROM ...
pie / donutcategory, valueSELECT status AS category, COUNT(*) AS value FROM ...
heatmapx, y, valueSELECT hour AS x, day AS y, COUNT(*) AS value FROM ...
treemapcategory, value, parentSELECT name AS category, size AS value, parent FROM ...

Use CHART_REQUIRED_ALIASES and validateChartAliases to check at runtime:

import { CHART_REQUIRED_ALIASES, validateChartAliases } from "@duckviz/widgets";

// Get required aliases for a chart type
const aliases = CHART_REQUIRED_ALIASES["bar"]; // ["category", "value"]

// Validate that query results have the right columns
const data = await db.runQuery(widget.duckdbQuery);
const valid = validateChartAliases(widget.type, data);

Row caps + error boundary

Every D3 chart has a hard row ceiling — SVG stops painting past a few thousand nodes. The cap is applied via applyChartCap() and the badge via drawRowCapBadge() — both exported so you can use them outside the built-in charts.

ChartCapWhy
Table widget10Dashboard context, not a paginated grid
Bubble, Circle packing500SVG circle count + hover handlers
Parallel coordinates1 000One polyline per row
Heatmap2 000Cell count = rows × cols
Contour5 000Density estimation cost
import { applyChartCap, drawRowCapBadge, ChartErrorBoundary } from "@duckviz/widgets";

const { rows, total, capped } = applyChartCap(allRows, { max: 2000 });
if (capped) drawRowCapBadge(svgGroup, { shown: rows.length, total });

<ChartErrorBoundary> wraps any chart subtree and renders a small inline fallback on render throws. Reset key is computed from (query, type, rowCount) so editing the SQL or swapping viz type retries automatically — used internally by @duckviz/dashboard@0.7.1+, safe to use yourself when rendering charts outside the <Dashboard> grid.

Chart utility functions

Shared utilities for building D3 charts:

import {
  CHART_COLORS,        // Default color palette (theme-aware)
  toNum,               // Safe number coercion
  toStr,               // Safe string coercion
  fmtNum,              // Format numbers (1234 → "1.2K")
  createChartTooltip,  // Create a tooltip div
  positionTooltip,     // Position tooltip relative to container
  appendLegend,        // Add a color legend to a chart
  LEGEND_WIDTH,        // Legend reserved width (px)
  buildXTickFormatter, // Build a tick formatter for X axis
  cullXTicks,          // Remove overlapping X axis labels
  applyChartCap,       // Truncate rows to chart's hard limit
  drawRowCapBadge,     // Render the "Showing N of M" badge
  useD3Container,      // React hook for D3 container ref
} from "@duckviz/widgets";

All theme-token lookups (CHART_COLORS, axis fill, subtle text) resolve via getComputedStyle(document.documentElement) — hex values are only a last-resort fallback. Don't pass raw var(--token) strings into D3 color scales; D3 can't parse them and charts render black.

fmtNum(n)

Formats numbers for chart labels:

fmtNum(1234);      // "1.2K"
fmtNum(1500000);   // "1.5M"
fmtNum(0.456);     // "0.46"
fmtNum(42);        // "42"

useD3Container()

React hook that returns a ref and dimensions for D3 charts:

const { containerRef, width, height } = useD3Container();

Chart categories

The registry includes 80+ chart types across 15 categories. See the full chart type reference for the complete list.

CategoryExamples
Barbar, grouped-bar, stacked-bar, horizontal-bar, diverging-bar
Lineline, multi-line, area, stacked-area, step
Scatterscatter, bubble, hexbin, contour
Piepie, donut, waffle
Distributionhistogram, box-plot, violin, ridgeline
Heatmapheatmap, calendar-heatmap
Hierarchytreemap, sunburst, circle-packing
Networkforce-directed, chord, sankey, arc-diagram
Radialradial-bar, radar, gauge
Textword-cloud, table
Specialtycandlestick, gantt, timeline, bullet, lollipop, dumbbell, bump-chart