How to Work with Astryx Chart Components and Vega Integration
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 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) 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:
- Schema validation —
parseSchema([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. - Compilation — Vega‑Lite specs are processed through
compile(spec, compileOptions).spec. - Parsing — The resulting Vega spec passes through
vega.parse(vegaSpec, parseConfig, parseOptions). - View instantiation — A
new View(runtime, viewOptions)is created and bound to the container<div>. - Data hydration — Initial datasets load via
view.data(name, tuples)before the first render. - Async execution —
view.runAsync()triggers rendering, followed byonReadyoronErrorcallbacks.
All configuration objects map directly to underlying Vega APIs, allowing fine‑tuned control without leaving the Astryx abstraction.
Rendering Vega‑Lite Bar Charts
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
<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/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)) manages flow layout through computeLayout and distributes positions via SankeyProvider context.
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 × minColumnWidthexceeds 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)) automatically selects spider mode when axes are provided, otherwise operating in pie/donut mode.
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:
angleByAxismap 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
padAnglecreates 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/ follows identical Tier‑1 patterns. ThreeDChart ([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
<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
Summary
- Choose
VegaChartwhen you need full Vega/Vega‑Lite spec compatibility and direct runtime access; the component automatically compiles Vega‑Lite and exposes theViewinstance viaonReady - Choose
@astryxdesign/labcomponents for production scenarios requiring responsive layout, accessibility compliance, and minimal configuration - Update data via runtime APIs rather than props; initial
datais loaded once during mount, and subsequent changes useview.data()andview.runAsync() - Leverage built‑in accessibility — every Astryx chart exposes
role="img", acceptsaria-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/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/packages/vega/src/vegaLiteConfig.ts) helpers to build reusable configuration objects.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →