License npm Bundle Size JSR CI Discord
A modern, type-safe SolidJS component for Plotly.js charts with fine-grained reactivity and full event support.
- 🏭 Factory Pattern - Plotly-agnostic design, bring your own Plotly.js bundle
- ⚡ SolidJS Reactivity - Fine-grained reactive updates for optimal performance
- 📱 Responsive by Default - Automatic resizing with ResizeObserver
- 🎯 Full TypeScript Support - Complete type safety with comprehensive JSDoc
- 🎪 30+ Event Handlers - All official Plotly.js events supported
- Installation
- Plotly.js Distribution
- Quick Start
- API Reference
- Examples
- Customizing Plotly.js Bundle
- TypeScript Usage
- Development
npm install solid-js @dschz/solid-plotly # or pnpm add solid-js @dschz/solid-plotly # or yarn add solid-js @dschz/solid-plotly # or bun add solid-js @dschz/solid-plotly
Important: You must also install a Plotly.js distribution that suits your needs. This library is designed to be Plotly-agnostic, allowing you to choose the which PLotly distribution is optimal for the needs of your application.
npm install plotly.js-dist-min
# Full bundle (~3MB) - All chart types and features npm install plotly.js-dist # Basic bundle (~1MB) - Common chart types (scatter, bar, line, pie, etc.) npm install plotly.js-basic-dist # Minimal bundle (~400KB) - Essential charts only npm install plotly.js-dist-min # Custom build - Advanced users who want to cherry-pick modules npm install plotly.js
Create a Plot component using the factory function with your chosen Plotly.js bundle:
import { createSignal } from "solid-js"; import Plotly from "plotly.js-dist-min"; import { createPlotComponent } from "@dschz/solid-plotly"; // Create the Plot component bound to your Plotly module const Plot = createPlotComponent(Plotly); function App() { return ( <Plot data={[ { x: [1, 2, 3], y: [2, 6, 3], type: "scatter", mode: "lines+markers", marker: { color: "red" }, }, { type: "bar", x: [1, 2, 3], y: [2, 5, 3] }, ]} layout={{ title: "My First Chart" }} onClick={(event) => console.log("Clicked:", event.points)} /> ); }
Creates a Plot component bound to a specific Plotly.js module.
Parameters:
Plotly- Plotly.js module with required methods:newPlot,react,purge,Plots
Returns: SolidJS component for rendering Plotly charts
import Plotly from "plotly.js-basic-dist"; import { createPlotComponent } from "@dschz/solid-plotly"; const Plot = createPlotComponent(Plotly);
| Prop | Type | Default | Description |
|---|---|---|---|
data |
PlotlyData[] |
[] |
Array of data traces to plot (required) |
layout |
PlotlyLayout |
{} |
Layout configuration for axes, title, margins, etc. |
config |
PlotlyConfig |
{} |
Plotly configuration options for behavior and appearance |
frames |
PlotlyFrame[] |
[] |
Animation frames for animated plots |
useResize |
boolean |
true |
Enable automatic plot resizing when container size changes |
id |
string |
"solid-plotly" |
Unique identifier for the plot container element |
class |
string |
undefined |
CSS class name(s) to apply to the plot container |
style |
JSX.CSSProperties |
{ position: "relative", display: "inline-block" } |
Inline CSS styles for the plot container |
onInitialized |
(figure, element) => void |
undefined |
Callback fired when the plot is first initialized |
onUpdate |
(figure, element) => void |
undefined |
Callback fired when the plot data/layout is updated |
onPurge |
(figure, element) => void |
undefined |
Callback fired when the plot is purged/destroyed |
onResize |
() => void |
undefined |
Callback fired when the plot is resized |
onError |
(error) => void |
undefined |
Callback fired when an error occurs during plot operations |
ref |
(el: HTMLDivElement) => void |
undefined |
Ref callback to access the underlying HTML div element |
The component supports all official Plotly.js events through props. All event handlers are optional:
onClick- Fired when a data point is clickedonDoubleClick- Fired when plot is double-clickedonHover- Fired when hovering over a data pointonUnhover- Fired when mouse leaves a data point
onSelected- Fired when data points are selectedonSelecting- Fired continuously while selecting data pointsonDeselect- Fired when selection is cleared
onRelayout- Fired when the plot layout is changed (zoom, pan, resize)onRelayouting- Fired continuously while the layout is being changedonRestyle- Fired when plot styling properties are changed
onLegendClick- Fired when a legend item is clickedonLegendDoubleClick- Fired when a legend item is double-clicked
onClickAnnotation- Fired when an annotation is clickedonSliderChange- Fired when a slider value is changedonSliderStart- Fired when slider interaction startsonSliderEnd- Fired when slider interaction ends
onAfterPlot- Fired after plot rendering completesonBeforePlot- Fired before plot rendering beginsonRedraw- Fired when plot is redrawnonAutoSize- Fired when plot auto-resizes
onAnimated- Fired after animation completesonAnimatingFrame- Fired when an animation frame is being processedonAnimationInterrupted- Fired when animation is interruptedonTransitioning- Fired during plot transitionsonTransitionInterrupted- Fired when transition is interrupted
onAfterExport- Fired after export operation completesonBeforeExport- Fired before export operation begins
onFramework- Fired for framework-specific eventsonSunburstClick- Fired when a sunburst chart segment is clickedonEvent- Generic event handler for any plot event
import { createSignal } from "solid-js"; import Plotly from "plotly.js-dist-min"; import { createPlotComponent, type PlotlyData } from "@dschz/solid-plotly"; const Plot = createPlotComponent(Plotly); function ReactivePlot() { const [data, setData] = createSignal<PlotlyData[]>([ { x: [1, 2, 3], y: [1, 4, 2], type: "scatter" }, ]); const addPoint = () => { setData((prev) => [ { ...prev[0], x: [...prev[0].x, prev[0].x.length + 1], y: [...prev[0].y, Math.random() * 10], }, ]); }; return ( <div> <button onClick={addPoint}>Add Point</button> <Plot data={data()} layout={{ title: "Reactive Updates" }} /> </div> ); }
import { createSignal } from "solid-js"; import type { PlotSelectionEvent } from "plotly.js"; import { createPlotComponent, type PlotlyData, type PlotlyLayout } from "@dschz/solid-plotly"; const Plot = createPlotComponent(Plotly); function InteractivePlot() { const [selectedPoints, setSelectedPoints] = createSignal<PlotSelectionEvent["points"]>([]); const [data] = createSignal<PlotlyData[]>([ { x: [1, 2, 3, 4], y: [10, 11, 12, 13], type: "scatter" }, ]); const [layout] = createSignal<PlotlyLayout>({ title: "Click and Select Points" }); return ( <Plot data={data()} layout={layout()} onClick={(event) => { console.log("Clicked point:", event.points[0]); }} onSelected={(event) => { setSelectedPoints(event.points); console.log("Selected points:", event.points.length); }} onRelayout={(event) => { console.log("Layout changed:", event); }} /> ); }
import { createSignal } from "solid-js"; import { createPlotComponent, type PlotlyData, type PlotlyLayout } from "@dschz/solid-plotly"; const Plot = createPlotComponent(Plotly); function ResponsivePlot() { const [data] = createSignal<PlotlyData[]>([{ x: [1, 2, 3], y: [1, 4, 2], type: "scatter" }]); const [layout] = createSignal<PlotlyLayout>({ title: "Responsive Chart" }); return ( <div style={{ width: "100%", height: "400px" }}> <Plot data={data()} layout={layout()} useResize={true} // Default: true style={{ width: "100%", height: "100%" }} /> </div> ); }
import { createSignal, createEffect, onCleanup } from "solid-js"; import { createPlotComponent, type PlotlyData, type PlotlyLayout } from "@dschz/solid-plotly"; const Plot = createPlotComponent(Plotly); function AnimatedPlot() { const [frame, setFrame] = createSignal(0); const [isAnimating, setIsAnimating] = createSignal(false); const [layout] = createSignal<PlotlyLayout>({ title: "Animated Sine Wave" }); createEffect(() => { if (!isAnimating()) return; const interval = setInterval(() => { setFrame((prev) => (prev + 1) % 60); }, 100); onCleanup(() => clearInterval(interval)); }); const data = (): PlotlyData[] => [ { x: Array.from({ length: 50 }, (_, i) => i * 0.1), y: Array.from({ length: 50 }, (_, i) => Math.sin(i * 0.1 + frame() * 0.1)), type: "scatter", mode: "lines", }, ]; return ( <div> <button onClick={() => setIsAnimating(!isAnimating())}> {isAnimating() ? "Stop" : "Start"} Animation </button> <Plot data={data()} layout={layout()} /> </div> ); }
Choose the Plotly.js bundle that best fits your needs:
// Full bundle (~3MB) - All chart types import Plotly from "plotly.js-dist"; const Plot = createPlotComponent(Plotly); // Basic bundle (~1MB) - Common chart types import Plotly from "plotly.js-basic-dist"; const Plot = createPlotComponent(Plotly); // Minimal bundle (~400KB) - Essential charts only import Plotly from "plotly.js-dist-min"; const Plot = createPlotComponent(Plotly);
The library provides comprehensive TypeScript support with utility types to reduce friction when defining your chart data and configurations:
import { createSignal } from "solid-js"; import { createPlotComponent, type PlotlyData, type PlotlyLayout, type PlotlyConfig, type PlotlyFigure, type PlotProps, } from "@dschz/solid-plotly"; // Use utility types for your signals const [data, setData] = createSignal<PlotlyData[]>([ { x: [1, 2, 3], y: [1, 4, 2], type: "scatter" }, ]); const [layout, setLayout] = createSignal<PlotlyLayout>({ title: "My Chart", xaxis: { title: "X Axis" }, yaxis: { title: "Y Axis" }, }); const [config, setConfig] = createSignal<PlotlyConfig>({ displayModeBar: true, responsive: true, }); // Type-safe callbacks const handleInitialized = (figure: PlotlyFigure, element: PlotlyHTMLElement) => { console.log("Initialized with", figure.data.length, "traces"); setData(figure.data); setLayout(figure.layout); }; // Create your Plot component const Plot = createPlotComponent(Plotly); function MyChart() { return ( <Plot data={data()} layout={layout()} config={config()} onInitialized={handleInitialized} /> ); }
PlotlyData- Single data trace type (usePlotlyData[]for the data prop)PlotlyLayout- Layout configuration objectPlotlyConfig- Plotly configuration optionsPlotlyFrame- Animation frame type (usePlotlyFrame[]for frames prop)PlotlyFigure- Complete figure data structure (used in callbacks)PlotProps- Complete props interface for the Plot componentPlotlyModule- Type for the Plotly.js module interface
Contributions are welcome! Please feel free to submit a Pull Request.
For more examples and detailed documentation, visit the GitHub repository or check out the Discord community.
MIT License