@arshad-shah/swift-chart
v1.3.0
Published
Lightning-fast, zero-dependency Canvas 2D charting library with React bindings. Schema-agnostic, themeable, animated.
Maintainers
Readme
SwiftChart
Lightning-fast, zero-dependency Canvas 2D charting library with first-class React bindings. 25 chart types, tree-shakeable, schema-agnostic, animated.
📖 Full documentation, live previews, and API reference →
npm install @arshad-shah/swift-chartWhy SwiftChart?
SwiftChart bundle size is measured from dist/esm/index.js at the current commit. Other libraries' figures are approximate min+gzip values from bundlephobia for their current major versions.
Quick start
Vanilla JS
import { LineChart } from '@arshad-shah/swift-chart';
const chart = new LineChart('#my-chart', {
title: 'Revenue',
theme: 'midnight',
area: true,
});
// Pass any data shape — SwiftChart auto-detects fields.
chart.setData(apiResponse, { x: 'date', y: 'revenue' });React
import { Line, Bar, Donut } from '@arshad-shah/swift-chart/react';
function Dashboard() {
return (
<div style={{ display: 'grid', gap: 16 }}>
<Line
data={salesData}
mapping={{ x: 'month', y: ['revenue', 'target'] }}
theme="midnight"
height={300}
area
/>
<Bar
data={regionData}
mapping={{ x: 'region', y: 'sales' }}
theme="arctic"
height={300}
/>
<Donut
data={trafficData}
mapping={{ labelField: 'source', valueField: 'visits' }}
height={300}
/>
</div>
);
}Chart types
25 chart types, grouped by family. Every entry is exported from both the vanilla entry (@arshad-shah/swift-chart) and the React entry (@arshad-shah/swift-chart/react).
Each chart has its own catalogue page with a live preview, full prop list, and code samples for both vanilla and React.
Schema-agnostic data
SwiftChart eats any shape of data:
// 1. Auto-detect: string field → labels, number fields → series.
chart.setData([
{ month: 'Jan', sales: 420, cost: 280 },
{ month: 'Feb', sales: 510, cost: 320 },
]);
// 2. Explicit mapping.
chart.setData(data, {
x: 'timestamp',
y: ['metric_a', 'metric_b'],
seriesNames: ['CPU', 'Memory'],
});
// 3. Pre-built format (Chart.js-compatible).
chart.setData([], {
labels: ['Q1', 'Q2', 'Q3'],
datasets: [{ label: 'Revenue', data: [100, 200, 350] }],
});See Data mapping → for the full resolver, including colorField / colorMap for per-datum colours.
Themes
4 built-in themes plus unlimited custom themes:
import { addTheme, LineChart } from '@arshad-shah/swift-chart';
// Built-in: 'midnight' | 'arctic' | 'ember' | 'forest'
new LineChart(el, { theme: 'midnight' });
// Custom theme
addTheme('neon', {
bg: '#0a0a0f',
surface: '#111118',
grid: '#ffffff08',
text: '#e0e0ff',
textMuted: '#6060a0',
axis: '#2a2a4a',
colors: ['#ff00ff', '#00ffff', '#ffff00', '#ff6600'],
});addTheme is also re-exported from @arshad-shah/swift-chart/react so React-only consumers can register without importing the core entry.
Tooltip colours derive from the active theme automatically (light themes get a light tooltip). See Theming →.
React refs and imperative control
import { useRef } from 'react';
import { Line, type ChartRef } from '@arshad-shah/swift-chart/react';
function MyChart() {
const ref = useRef<ChartRef>(null);
return (
<>
<Line ref={ref} data={data} mapping={mapping} />
<button onClick={() => ref.current?.resize()}>Resize</button>
<button onClick={() => download(ref.current?.toDataURL())}>Save PNG</button>
</>
);
}Click events / drill-down
Every chart's onClick (and the React onPointClick prop) receives a ChartClickEvent carrying the original row, the resolved series, the value, and the underlying MouseEvent:
<Bar
data={orders}
mapping={{ x: 'region', y: 'revenue' }}
onPointClick={(_i, _d, e) => {
// e.datum → original row from `orders`
// e.label → 'NA' | 'EU' | …
// e.value → numeric revenue
// e.nativeEvent.metaKey → ⌘ for "open in new tab" etc.
router.push(`/regions/${e.datum.id}`);
}}
/>Tap-to-click on touch devices and Enter/Space/Arrow-key activation on focused interactive charts both fire the same handler — see Click events → and Accessibility →.
Configuration
All charts accept these base options (chart-specific options are documented in each catalogue page):
interface BaseChartConfig {
theme?: 'midnight' | 'arctic' | 'ember' | 'forest' | Theme;
animate?: boolean; // default true (auto-disabled when prefers-reduced-motion is set)
animDuration?: number; // default 600ms
animEasing?: EasingName; // default 'easeOutCubic'
responsive?: boolean; // default true (auto-resize via ResizeObserver)
padding?: Partial<Padding>;
showGrid?: boolean; // default true
showTooltip?: boolean; // default true
showLegend?: boolean; // default true
legendPosition?: 'top' | 'bottom' | 'left' | 'right' | 'none'; // default 'top'
title?: string;
subtitle?: string;
formatValue?: (v: number) => string;
colorFn?: (value: number, dataIdx: number, seriesIdx: number) => string | undefined;
onClick?: (index: number, data: ResolvedData, event: ChartClickEvent) => void;
ariaLabel?: string;
ariaDescription?: string;
tooltipContainer?: HTMLElement; // portal target — defaults to chart container / shadow root
}Browser support
Canvas 2D + ResizeObserver: Chrome 64+, Firefox 69+, Safari 13.1+, Edge 79+.
Charts work inside Shadow DOM (web components), modals/popovers (the tooltip stays in the chart's stacking context), and behind overflow:auto scroll containers (scroll on any ancestor hides the tooltip cleanly).
Local development
pnpm install
pnpm test # run the test suite (1000+ tests)
pnpm validate # full CI chain: typecheck + lint + test + build + publint + attw + size
pnpm --filter swiftchart-docs dev # run the docs site locallyLicense
MIT © Arshad Shah
