Getting started · Frameworks
React
Install
| Package | @silverpoint/react |
| Peers | react and react-dom 18.2+ or 19; @knight-lab/timelinejs ^3.9.13 (optional, for SpTimeline) |
| Integration | Vite and Next.js (App Router, React Server Components) are validated. |
| Components | LineChart |
| Import from | @silverpoint/react/<chart> |
| App-wide configuration | SilverpointProvider |
npm install @silverpoint/react @silverpoint/grounds @silverpoint/fontsQuickstart
Create a fresh app and install silverpoint:
npm create vite@latest my-charts -- --template react-ts
cd my-charts
npm install @silverpoint/react @silverpoint/grounds @silverpoint/fonts
npm run devThen replace the app's entry with:
// src/App.tsx
import '@silverpoint/fonts/fonts.css';
import '@silverpoint/grounds/styles.css';
import { LineChart } from '@silverpoint/react/line-chart';
const data = [
{ hour: '00', hits: 18 },
{ hour: '04', hits: 11 },
{ hour: '08', hits: 42 },
{ hour: '12', hits: 64 },
{ hour: '16', hits: 57 },
{ hour: '20', hits: 30 },
];
export default function App() {
return (
<div style={{ width: 480 }}>
<LineChart data={data} xKey="hour" valueKey="hits" title="Hits per hour" />
</div>
);
}| hour | hits |
|---|---|
| 00 | 18 |
| 04 | 11 |
| 08 | 42 |
| 12 | 64 |
| 16 | 57 |
| 20 | 30 |
The chart takes the width of its container. height is the height of the drawing area and defaults to 160 px. Omit data and a chart draws its own demo dataset.
One ground for the whole app
Set the ground, the substrate, the mode and the locale once for every chart. A prop on a chart always wins.
import { SilverpointProvider } from '@silverpoint/react';
import { BarChart } from '@silverpoint/react/bar-chart';
import { DonutChart } from '@silverpoint/react/donut-chart';
export function Dashboard() {
return (
<SilverpointProvider ground="silverpoint" substrate="green" locale="en-GB">
<BarChart data={sales} xKey="month" valueKey="units" title="Units sold" unit="units" />
<DonutChart data={channels} nameKey="channel" valueKey="share" title="Sales by channel" centerLabel="%" />
</SilverpointProvider>
);
}| month | units |
|---|---|
| Jan | 120 |
| Feb | 98 |
| Mar | 143 |
| channel | share | share |
|---|---|---|
| Web | 54 | 54% |
| Stores | 31 | 31% |
| Partners | 15 | 15% |
Precision mode
<LineChart data={data} xKey="hour" valueKey="hits" title="Hits per hour" mode="precision" />Interaction and a custom readout
import { useState } from 'react';
import { LineChart } from '@silverpoint/react/line-chart';
export function Explorer({ data }: { data: { hour: string; hits: number }[] }) {
const [active, setActive] = useState<string>('—');
return (
<>
<LineChart
data={data}
xKey="hour"
valueKey="hits"
title="Hits per hour"
onActiveChange={(item) => setActive(item ? `${item.datum.hour}: ${item.value}` : '—')}
onSelect={(item) => console.log('selected', item.datum)}
tooltip={(item) => <strong>{item.value} hits</strong>}
/>
<p>Under the pointer: {active}</p>
</>
);
}Export: the imperative handle
import { useRef } from 'react';
import { LineChart, type ChartHandle } from '@silverpoint/react/line-chart';
export function Exportable({ data }: { data: { hour: string; hits: number }[] }) {
const chart = useRef<ChartHandle>(null);
const download = () => {
const svg = chart.current?.toSVGString() ?? '';
window.open(URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' })));
};
return (
<>
<LineChart ref={chart} data={data} xKey="hour" valueKey="hits" title="Hits per hour" />
<button onClick={download}>Export SVG</button>
</>
);
}Server rendering
// app/page.tsx — a React Server Component (Next.js App Router)
import '@silverpoint/fonts/fonts.css';
import '@silverpoint/grounds/styles.css';
import { LineChart } from '@silverpoint/react/server/line-chart';
const data = [
{ hour: '00', hits: 18 },
{ hour: '12', hits: 64 },
{ hour: '20', hits: 30 },
];
export default function Page() {
return <LineChart id="hits" width={480} height={160} data={data} xKey="hour" valueKey="hits" title="Hits per hour" />;
}UI components
Since 0.3: 17 interface components from @silverpoint/react/ui, drawn as the charts are. Import @silverpoint/grounds/ui.css once, beside styles.css. A form with a controlled input, a switch, tabs and a submit button:
import { useState, type FormEvent } from 'react';
import { SpButton, SpInput, SpSwitch, SpTabPanel, SpTabs } from '@silverpoint/react/ui';
import { BarChart } from '@silverpoint/react/bar-chart';
import { LineChart } from '@silverpoint/react/line-chart';
export function Settings() {
const [city, setCity] = useState('Caracas');
const [precision, setPrecision] = useState(false);
const [view, setView] = useState('traffic');
const mode = precision ? 'precision' : 'ink';
const save = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log(Object.fromEntries(new FormData(event.currentTarget))); // { city, precision, … }
};
return (
<form onSubmit={save}>
{/* onChange receives the value itself, not the DOM event */}
<SpInput label="City" name="city" value={city} onChange={setCity}
invalid={city === ''} message="Required: pick a city" />
<SpSwitch label="Precision" name="precision" checked={precision} onChange={setPrecision} />
<SpTabs label="Views" value={view} onChange={setView}
items={[{ key: 'traffic', label: 'Traffic' }, { key: 'errors', label: 'Errors' }]}>
<SpTabPanel value="traffic"><LineChart title="Traffic" mode={mode} /></SpTabPanel>
<SpTabPanel value="errors"><BarChart title="Errors" mode={mode} /></SpTabPanel>
</SpTabs>
<SpButton type="submit" variant="primary">Save</SpButton>
</form>
);
}Every component has a reference page with each of its states in this framework:
New in 0.8.0: palettes, overlays, timeline
21 more UI components from the same @silverpoint/react/ui subpaths — composed ones (table, pagination, statistic, collapse…) and overlays on the platform's <dialog> and Popover API (modal, drawer, popover, tooltip, select, menu, toast) —, a palette on every chart, component and provider, and SpTimeline on @silverpoint/react/timeline. An overlay opens from a trigger you write:
import { useState } from 'react';
import { SpButton } from '@silverpoint/react/ui/button';
import { SpModal } from '@silverpoint/react/ui/modal';
export function ApplyChanges() {
const [open, setOpen] = useState(false);
return (
<SpModal
title="Apply changes"
description="The geometry of the data does not move."
trigger={<button type="button">Open the modal</button>} // any element you write
footer={<SpButton variant="primary" onClick={() => setOpen(false)}>Apply</SpButton>}
open={open}
onOpenChange={setOpen}
>
<p>Apply the new ground to every chart on the page?</p>
</SpModal>
);
}Next.js and React Server Components
The default subpaths are client components ("use client") that work in the App Router and hydrate without a mismatch. For pure SVG with no client JavaScript, import from @silverpoint/react/server/<chart>: no interaction, and id, width and height are required outside a Dashboard.
The 60 charts
Every chart has a reference page with its example in this framework: