Support D3-backed chart types and a Vega-Lite widget for custom visualizations
- Dominant language
- Go
- Stars
- 730
- Forks
- 33
- Avg merge
- 11h 47m
- Merged PRs (30d)
- 18
Description
## What problem are you trying to solve?
DAC's `chart` widget is currently limited to the chart types Recharts can render cleanly (line, bar, area, pie, scatter, combo, funnel, sankey) plus a handful of bespoke React components. There is no way to express visualizations that go beyond this fixed list without forking the frontend.
- Common analytics visualizations such as treemaps, sunbursts, chord diagrams, force-directed networks, radial charts, and choropleth maps are not available.
- Power users who need a custom encoding (e.g. a scatter with size + color + faceting, a layered chart, or a domain-specific viz) have no declarative escape hatch in YAML or TSX.
- Recharts is built on D3, but D3's full capability is not exposed — users cannot opt into richer chart types without writing a new widget component upstream.
- TSX dashboards run server-side via Goja, so authors cannot drop in client-side D3 code either.
- The only current workaround is to fork DAC and add a new chart component, which creates maintenance and upgrade drift.
## Proposed solution
Add D3 capability to DAC in two complementary phases, both fully declarative and version-controllable.
### Phase 1 — Expand the `chart` widget with D3-backed chart types
Add new `chart:` values that render via D3 primitives (`d3-hierarchy`, `d3-force`, `d3-geo`, `d3-chord`) while keeping the existing `{columns, rows}` data contract. No new widget type, no user JS — just more chart types behind the same YAML/TSX surface.
```yaml
- name: Revenue by Product Hierarchy
type: chart
chart: treemap
sql: |
SELECT category, product, revenue
FROM product_revenue
group: [category, product]
value: revenue
- name: Account Relationships
type: chart
chart: force
sql: |
SELECT source_account, target_account, weight
FROM account_links
source: source_account
target: target_account
weight: weight
- name: Revenue by Region
type: chart
chart: geo
sql: |
SELECT country_code, revenue
FROM revenue_by_country
region: country_code
value: revenue
```
Initial chart types to support:
- `treemap`
- `sunburst`
- `chord`
- `force` (network / node-link)
- `radial` (radial bar / polar)
- `geo` (choropleth)
### Phase 2 — New `vega` widget type for custom visualizations
Add a 7th widget type that accepts a [Vega-Lite](https://vega.github.io/vega-lite/) spec as JSON/YAML. DAC injects the query result as `data.values` before render. This unlocks the long tail of custom visualizations without exposing arbitrary client-side JS.
```yaml
- name: Deal Size vs Close Rate
type: vega
sql: |
SELECT segment, deal_size, close_rate, deal_count
FROM segment_performance
spec:
mark: circle
encoding:
x: { field: deal_size, type: quantitative }
y: { field: close_rate, type: quantitative }
size: { field: deal_count, type: quantitative }
color: { field: segment, type: nominal }
```
Support should include:
- new D3-backed chart types behind the existing `chart` widget (Phase 1)
- a new `vega` widget type wrapping Vega-Lite via `react-vega` (Phase 2)
- per-chart-type field mappings (`group`, `value`, `source`, `target`, `region`, etc.) in YAML and TSX
- correct rendering in legends, tooltips, and the existing template system
- documentation and skill updates in `.claude/skills/create-dashboard/SKILL.md`
## Alternatives considered
- **Stick with Recharts only** — keeps the surface small but blocks every visualization Recharts cannot express, and users have already hit these limits.
- **Allow custom widget bundles** (`.widget.tsx` compiled at `dac build`) — most flexible, but introduces a client-side JS execution model, sandboxing/CSP questions, viewer trust, and a build pipeline. Better deferred until Phases 1 and 2 prove insufficient.
- **Recommend embedding external dashboards via iframe** — breaks the single-binary, dashboard-as-code model and removes version control of the visualization.
- **Fork DAC locally to add chart types** — works, but creates maintenance and upgrade drift, and every team ends up reinventing the same set of charts.
## Additional context
D3 is the de facto foundation for advanced data visualization on the web, and Vega-Lite is the established declarative grammar built on top of it (used by Streamlit, Apache Superset, Observable, and others). Both options preserve DAC's core principles: declarative authoring, version-controlled dashboards, no user JS in the browser at render time, and a single embedded binary.
Phase 1 is low risk and immediately unlocks the most-requested chart types; Phase 2 gives power users a declarative escape hatch for everything else. Phase 1 alone is likely to resolve the majority of "we need D3" requests, with Phase 2 as a follow-up if demand persists.
Contributor guide
Research direction
Start by tracing the existing chart widget and its `{columns, rows}` contract across the YAML and TSX surfaces. Review `.claude/skills/create-dashboard/SKILL.md` and the existing chart rendering, legend, tooltip, and template behavior before evaluating the D3-backed types and the proposed Vega-Lite widget. Done means both phases, field mappings, rendering behavior, and documentation updates are supported without arbitrary user JavaScript.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- d3, react, typescript, yaml
- Domain
- data-visualization, frontend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100