# How to Work with Astryx Chart Components and Vega Integration

> Master Astryx chart components and Vega integration. Use VegaChart and specialized components for powerful, accessible visualizations with data table fallbacks.

- Repository: [Meta/astryx](https://github.com/facebook/astryx)
- Tags: how-to-guide
- Published: 2026-08-05

---

**Use `VegaChart` from `@astryxdesign/vega` for declarative Vega/Vega‑Lite specs, or specialized components like `SankeyChart` and `RadialChart` from `@astryxdesign/lab` for built‑in layout, accessibility, and data‑table fallbacks.**

Astryx provides two distinct paths for building visualizations: a thin React wrapper around the Vega runtime for full spec control, and higher‑level chart primitives with automatic accessibility features. Both approaches follow Tier‑1 architecture principles where a single root component owns the rendering lifecycle and supplies context to children. This guide walks through the implementation details, practical patterns, and key source files in the [facebook/astryx](https://github.com/facebook/astryx) repository.

## Two Integration Paths for Astryx Charts

The library organizes its visualization capabilities across separate packages based on your needs.

| Path | Use Case | Primary Component | Package |
|------|----------|-------------------|---------|
| **Declarative Vega/Vega‑Lite** | Render any custom spec with full Vega ecosystem compatibility | `VegaChart` | `@astryxdesign/vega` |
| **Higher‑level primitives** | Production‑ready charts with responsive layout, accessibility, and minimal configuration | `SankeyChart`, `RadialChart`, `ThreeDChart` | `@astryxdesign/lab` |

Both paths share core design principles: **accessibility first** (every chart exposes `role="img"` with overridable `aria-label`), **non‑reactive data loading** (initial data is loaded once; updates use the runtime API), and **single‑root lifecycle ownership**.

## VegaChart: Deep Vega Integration

`VegaChart` in [[`packages/vega/src/VegaChart.tsx`](https://github.com/facebook/astryx/blob/main/packages/vega/src/VegaChart.tsx)](https://github.com/facebook/astryx/blob/main/packages/vega/src/VegaChart.tsx) provides complete access to the Vega runtime through a React‑friendly API.

### How VegaChart Processes Specifications

The component inspects `spec.$schema` to determine whether compilation is needed:

1. **Schema validation** — `parseSchema` ([[`src/schema.ts`](https://github.com/facebook/astryx/blob/main/src/schema.ts)](https://github.com/facebook/astryx/blob/main/packages/vega/src/schema.ts)) parses the URL and identifies Vega‑Lite vs. native Vega.
2. **Compilation** — Vega‑Lite specs are processed through `compile(spec, compileOptions).spec`.
3. **Parsing** — The resulting Vega spec passes through `vega.parse(vegaSpec, parseConfig, parseOptions)`.
4. **View instantiation** — A `new View(runtime, viewOptions)` is created and bound to the container `<div>`.
5. **Data hydration** — Initial datasets load via `view.data(name, tuples)` before the first render.
6. **Async execution** — `view.runAsync()` triggers rendering, followed by `onReady` or `onError` callbacks.

All configuration objects map directly to underlying Vega APIs, allowing fine‑tuned control without leaving the Astryx abstraction.

### Rendering Vega‑Lite Bar Charts

```tsx
import {VegaChart} from '@astryxdesign/vega';

const spec = {
  $schema: 'https://vega.github.io/schema/vega-lite/v5.json',
  mark: 'bar',
  data: {name: 'table'},
  encoding: {
    x: {field: 'category', type: 'ordinal'},
    y: {field: 'value', type: 'quantitative'}
  }
};

function App() {
  return (
    <VegaChart
      spec={spec}
      data={{table: [
        {category: 'A', value: 30},
        {category: 'B', value: 55}
      ]}}
      onReady={view => {
        // Attach signal listeners or update data dynamically
        view.addSignalListener('click', (_, value) => {
          console.log('clicked', value);
        });
      }}
    />
  );
}

```

**Critical pattern:** The `data` prop is **not reactive**. After mount, updates must use the `view` instance received in `onReady` via `view.data()` and `view.runAsync()`.

### Customizing Vega View Options

```tsx
<VegaChart
  spec={vegaSpec}
  viewOptions={{
    logLevel: 1,                     // Debug logging
    tooltip: (handler, event) => {   // Custom tooltip implementation
      // Custom handler logic
    },
    background: '#fafafa'
  }}
  compileOptions={{
    config: {mark: {tooltip: true}}
  }}
/>

```

The `viewOptions` object in [[`src/types.ts`](https://github.com/facebook/astryx/blob/main/src/types.ts)](https://github.com/facebook/astryx/blob/main/packages/vega/src/types.ts) exposes all Vega `View` constructor parameters, while `compileOptions` configures Vega‑Lite compilation behavior.

## Higher‑Level Chart Components

The `@astryxdesign/lab` package provides purpose‑built components with automatic layout computation and accessibility features.

### SankeyChart for Flow Visualizations

`SankeyChart` ([[`packages/lab/src/Sankey/SankeyChart.tsx`](https://github.com/facebook/astryx/blob/main/packages/lab/src/Sankey/SankeyChart.tsx)](https://github.com/facebook/astryx/blob/main/packages/lab/src/Sankey/SankeyChart.tsx)) manages flow layout through `computeLayout` and distributes positions via `SankeyProvider` context.

```tsx
import {
  SankeyChart,
  SankeyNode,
  SankeyLink,
  SankeyGrid,
  SankeyLabel
} from '@astryxdesign/lab';

const nodes = [
  {id: 'a', label: 'Source A'},
  {id: 'b', label: 'Source B'},
  {id: 'c', label: 'Target C'}
];

const links = [
  {source: 'a', target: 'c', value: 10},
  {source: 'b', target: 'c', value: 20}
];

function RevenueFlow() {
  return (
    <SankeyChart
      nodes={nodes}
      links={links}
      minColumnWidth={200}
      label="Revenue flow by channel"
    >
      <SankeyGrid />
      <SankeyLink />
      <SankeyNode />
      <SankeyLabel />
    </SankeyChart>
  );
}

```

**Key behaviors:**
- **Responsive width** — expands to container; horizontal scrolling activates when `columns × minColumnWidth` exceeds available space
- **Accessible scrolling** — scrollable regions receive proper accessible names
- **Data table fallback** — for ≤ 100 links, a visually hidden HTML table with "From / To / Value" columns supports screen readers

### RadialChart: Spider and Pie Modes

`RadialChart` ([[`packages/lab/src/Radial/RadialChart.tsx`](https://github.com/facebook/astryx/blob/main/packages/lab/src/Radial/RadialChart.tsx)](https://github.com/facebook/astryx/blob/main/packages/lab/src/Radial/RadialChart.tsx)) automatically selects **spider mode** when `axes` are provided, otherwise operating in **pie/donut mode**.

```tsx
import {
  RadialChart,
  RadialAxis,
  RadialArea,
  RadialGrid
} from '@astryxdesign/lab';

const data = [
  {model: 'A', speed: 7, handling: 5, comfort: 6},
  {model: 'B', speed: 6, handling: 8, comfort: 7}
];

function PerformanceRadar() {
  return (
    <RadialChart
      data={data}
      axes={['speed', 'handling', 'comfort']}
      height={400}
      label="Vehicle performance comparison"
    >
      <RadialGrid rings={5} />
      <RadialArea dataKey="model" color="#4a90e2" />
      <RadialAxis />
    </RadialChart>
  );
}

```

**Spider mode calculations:**
- `angleByAxis` map computes angular position for each axis
- Per‑axis domains drive radial scale calculations

**Pie mode calculations:**
- Values are aggregated and converted to slice start/end angles
- Optional `padAngle` creates separation between slices

Both modes include automatic data table generation when total data points fall below the `MAX_TABLE_POINTS` threshold (6 points in the example above).

### ThreeDChart for WebGL Visualizations

The 3‑D family in [`packages/lab/src/ThreeD/`](https://github.com/facebook/astryx/blob/main/packages/lab/src/ThreeD/) follows identical Tier‑1 patterns. `ThreeDChart` ([[`ThreeDChart.tsx`](https://github.com/facebook/astryx/blob/main/ThreeDChart.tsx)](https://github.com/facebook/astryx/blob/main/packages/lab/src/ThreeD/ThreeDChart.tsx)) exposes `ThreeDProvider` context for projection matrices and camera interaction handling.

## Data Update Patterns

Astryx charts use **initial data loading** rather than reactive updates. This design choice prevents expensive recomputation on every render.

| Approach | Method | Use Case |
|----------|--------|----------|
| Vega runtime | `view.data(name, newTuples).runAsync()` | Dynamic data streaming, filtering, or updates |
| Re‑mount component | Change `key` prop | Complete spec or configuration change |

### Vega Runtime Update Example

```tsx
<VegaChart
  spec={spec}
  onReady={view => {
    // Store view reference for external updates
    window.chartView = view;
  }}
/>

// Later, from an event handler or data fetch:
window.chartView.data('table', newData);
window.chartView.runAsync();

```

## Source File Reference

| Component | File Path | Purpose |
|-----------|-----------|---------|
| `VegaChart` | [[`packages/vega/src/VegaChart.tsx`](https://github.com/facebook/astryx/blob/main/packages/vega/src/VegaChart.tsx)](https://github.com/facebook/astryx/blob/main/packages/vega/src/VegaChart.tsx) | Root component, Vega `View` lifecycle management |
| Type definitions | [[`packages/vega/src/types.ts`](https://github.com/facebook/astryx/blob/main/packages/vega/src/types.ts)](https://github.com/facebook/astryx/blob/main/packages/vega/src/types.ts) | `VegaChart` props, spec types, callback signatures |
| Schema parsing | [[`packages/vega/src/schema.ts`](https://github.com/facebook/astryx/blob/main/packages/vega/src/schema.ts)](https://github.com/facebook/astryx/blob/main/packages/vega/src/schema.ts) | `$schema` URL parsing, library detection |
| Vega‑Lite configuration | [[`packages/vega/src/vegaLiteConfig.ts`](https://github.com/facebook/astryx/blob/main/packages/vega/src/vegaLiteConfig.ts)](https://github.com/facebook/astryx/blob/main/packages/vega/src/vegaLiteConfig.ts) | Reusable config object builders |
| `SankeyChart` | [[`packages/lab/src/Sankey/SankeyChart.tsx`](https://github.com/facebook/astryx/blob/main/packages/lab/src/Sankey/SankeyChart.tsx)](https://github.com/facebook/astryx/blob/main/packages/lab/src/Sankey/SankeyChart.tsx) | Flow layout, responsive scrolling, accessibility |
| `RadialChart` | [[`packages/lab/src/Radial/RadialChart.tsx`](https://github.com/facebook/astryx/blob/main/packages/lab/src/Radial/RadialChart.tsx)](https://github.com/facebook/astryx/blob/main/packages/lab/src/Radial/RadialChart.tsx) | Spider/pie mode, angular calculations |
| `ThreeDChart` | [[`packages/lab/src/ThreeD/ThreeDChart.tsx`](https://github.com/facebook/astryx/blob/main/packages/lab/src/ThreeD/ThreeDChart.tsx)](https://github.com/facebook/astryx/blob/main/packages/lab/src/ThreeD/ThreeDChart.tsx) | Projection math, camera context |

## Summary

- **Choose `VegaChart`** when you need full Vega/Vega‑Lite spec compatibility and direct runtime access; the component automatically compiles Vega‑Lite and exposes the `View` instance via `onReady`
- **Choose `@astryxdesign/lab` components** for production scenarios requiring responsive layout, accessibility compliance, and minimal configuration
- **Update data via runtime APIs** rather than props; initial `data` is loaded once during mount, and subsequent changes use `view.data()` and `view.runAsync()`
- **Leverage built‑in accessibility** — every Astryx chart exposes `role="img"`, accepts `aria-label`, and generates hidden data tables for small datasets

## Frequently Asked Questions

### How does VegaChart detect whether a spec is Vega or Vega‑Lite?

`VegaChart` calls `parseSchema` from [[`src/schema.ts`](https://github.com/facebook/astryx/blob/main/src/schema.ts)](https://github.com/facebook/astryx/blob/main/packages/vega/src/schema.ts) to inspect `spec.$schema`. If the URL contains `vega-lite`, the component runs `vegaLite.compile()` before parsing; otherwise it passes the spec directly to `vega.parse()`.

### Can I update chart data without re‑mounting the component?

Yes. Capture the `view` instance in the `onReady` callback, then call `view.data(name, newTuples)` followed by `view.runAsync()`. The `data` prop is intentionally non‑reactive to prevent performance overhead on every render.

### What accessibility features are built into Astryx charts?

All charts render with `role="img"` and accept an `aria-label` prop. For datasets with ≤ 100 points (links in Sankey, rows×axes in Radial), a visually hidden `<table>` is automatically generated containing the raw data for screen‑reader users. Scrollable regions in `SankeyChart` receive additional accessible naming.

### Where should I configure Vega‑Lite compilation options?

Pass a `compileOptions` prop to `VegaChart`. This object is forwarded directly to `vegaLite.compile(spec, compileOptions)`. You can also use [[`vegaLiteConfig.ts`](https://github.com/facebook/astryx/blob/main/vegaLiteConfig.ts)](https://github.com/facebook/astryx/blob/main/packages/vega/src/vegaLiteConfig.ts) helpers to build reusable configuration objects.