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