Skip to content
silverpoint
Documentation menu

Getting started · Frameworks

React

Everything you need to use silverpoint with React: install, quickstart, app-wide configuration, precision mode, interaction, export, server rendering, the UI components and what 0.7 adds.

Install

Package@silverpoint/react
Peersreact and react-dom 18.2+ or 19; @knight-lab/timelinejs ^3.9.13 (optional, for SpTimeline)
IntegrationVite and Next.js (App Router, React Server Components) are validated.
ComponentsLineChart
Import from@silverpoint/react/<chart>
App-wide configurationSilverpointProvider
shell
npm install @silverpoint/react @silverpoint/grounds @silverpoint/fonts

Quickstart

Create a fresh app and install silverpoint:

shell
npm create vite@latest my-charts -- --template react-ts
cd my-charts
npm install @silverpoint/react @silverpoint/grounds @silverpoint/fonts
npm run dev

Then replace the app's entry with:

tsx
// 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>
  );
}
Hits per hourHits per hour
Hits per hour
hourhits
0018
0411
0842
1264
1657
2030

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.

tsx
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>
  );
}
Units soldUnits sold
Units sold
monthunits
Jan120
Feb98
Mar143
Sales by channelSales by channel
Sales by channel
channelshareshare
Web5454%
Stores3131%
Partners1515%

Precision mode

tsx
<LineChart data={data} xKey="hour" valueKey="hits" title="Hits per hour" mode="precision" />

Interaction and a custom readout

tsx
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

tsx
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

tsx
// 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:

tsx
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>
  );
}
Overview: the charts of this view.

Every component has a reference page with each of its states in this framework:

UI components: values, forms, keyboard →

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:

tsx
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: