# react-plotly.js

![plotly-react-logo](plotly-react-logo.png)

> A [plotly.js](https://github.com/plotly/plotly.js) React component from
> [Plotly](https://plotly.com/).

<div align="center">
  <a href="https://dash.plotly.com/project-maintenance">
    <img src="https://dash.plotly.com/assets/images/maintained-by-plotly.png" width="400px" alt="Maintained by Plotly">
  </a>
</div>

---

## Contents

- [Installation](#installation)
- [Quick start](#quick-start)
- [State management](#state-management)
- [Refreshing the Plot](#refreshing-the-plot)
- [API](#api-reference)
  - [Basic props](#basic-props)
  - [Event handler props](#event-handler-props)
- [Examples](#examples)
  - [Responsive plot](#responsive-plot)
  - [Event handlers](#event-handlers)
  - [TypeScript](#typescript)
  - [Grabbing the graph div via `ref`](#grabbing-the-graph-div-via-ref)
- [Customizing the `plotly.js` bundle](#customizing-the-plotlyjs-bundle)
- [Loading from a `<script>` tag](#loading-from-a-script-tag)
- [Development](#development)

## Installation

```bash
$ npm install react-plotly.js plotly.js
```

## Quick start

The easiest way to use this component is to import and pass data to a plot component:

```javascript
import Plot from 'react-plotly.js';

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={{width: 320, height: 240, title: {text: 'A Fancy Plot'}}}
    />
  );
}
```

You should see a plot like this:

<p align="center">
 <img src="example.png" alt="Example plot" width="320" height="240">
</p>

For a full description of Plotly chart types and attributes see the following resources:

- [Plotly JavaScript API documentation](https://plotly.com/javascript/)
- [Full plotly.js attribute listing](https://plotly.com/javascript/reference/)

## State management

This is a "dumb" component that doesn't merge its internal state with any updates. This means that if a user interacts with the plot, by zooming or panning for example, any subsequent re-renders will lose this information unless it is captured and upstreamed via the `onUpdate` callback prop.

Here is a simple example of how to capture and store state in a parent object:

```javascript
import {useState} from 'react';
import Plot from 'react-plotly.js';

function App() {
  const [figure, setFigure] = useState({data: [], layout: {}, frames: [], config: {}});
  return (
    <Plot
      data={figure.data}
      layout={figure.layout}
      frames={figure.frames}
      config={figure.config}
      onInitialized={setFigure}
      onUpdate={setFigure}
    />
  );
}
```

## Refreshing the Plot

This component will refresh the plot via [`Plotly.react`](https://plotly.com/javascript/plotlyjs-function-reference/#plotlyreact) if any of the following are true:

- The `revision` prop is defined and has changed, OR;
- One of `data`, `layout` or `config` has changed identity as checked via a shallow `===`, OR;
- The number of elements in `frames` has changed

Furthermore, when called, [`Plotly.react`](https://plotly.com/javascript/plotlyjs-function-reference/#plotlyreact) will only refresh the data being plotted if the _identity_ of the data arrays (e.g. `x`, `y`, `marker.color` etc) has changed, or if `layout.datarevision` has changed.

In short, this means that simply adding data points to a trace in `data` or changing a value in `layout` will not cause a plot to update unless this is done immutably via something like [immutability-helper](https://github.com/kolodny/immutability-helper) if performance considerations permit it, or unless `revision` and/or [`layout.datarevision`](https://plotly.com/javascript/reference/#layout-datarevision) are used to force a rerender.

## API Reference

### Basic Props

**Warning**: for the time being, this component may _mutate_ its `layout` and `data` props in response to user input, going against React rules. This behaviour will change in the near future once https://github.com/plotly/plotly.js/issues/2389 is completed.

| Prop               | Type                         | Default                                           | Description                                                                                                                                            |
| ------------------ | ---------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `data`             | `Array`                      | `[]`                                              | list of trace objects (see https://plotly.com/javascript/reference/)                                                                                      |
| `layout`           | `Object`                     | `undefined`                                       | layout object (see https://plotly.com/javascript/reference/#layout)                                                                                       |
| `frames`           | `Array`                      | `undefined`                                       | list of frame objects (see https://plotly.com/javascript/reference/)                                                                                      |
| `config`           | `Object`                     | `undefined`                                       | config object (see https://plotly.com/javascript/configuration-options/)                                                                                  |
| `revision`         | `Number`                     | `undefined`                                       | When provided, causes the plot to update when the revision is incremented.                                                                             |
| `onInitialized`    | `Function(figure, graphDiv)` | `undefined`                                       | Callback executed after plot is initialized. See below for parameter information.                                                                      |
| `onUpdate`         | `Function(figure, graphDiv)` | `undefined`                                       | Callback executed when a plot is updated due to new data or layout, or when user interacts with a plot. See below for parameter information.           |
| `onPurge`          | `Function(figure, graphDiv)` | `undefined`                                       | Callback executed when component unmounts, before `Plotly.purge` strips the `graphDiv` of all private attributes. See below for parameter information. |
| `onError`          | `Function(err)`              | `undefined`                                       | Callback executed when a plotly.js API method rejects                                                                                                  |
| `divId`            | `string`                     | `undefined`                                       | id assigned to the `<div>` into which the plot is rendered.                                                                                            |
| `className`        | `string`                     | `undefined`                                       | applied to the `<div>` into which the plot is rendered                                                                                                 |
| `style`            | `Object`                     | `{position: 'relative', display: 'inline-block'}` | used to style the `<div>` into which the plot is rendered                                                                                              |
| `debug`            | `Boolean`                    | `false`                                           | Assign the graph div to `window.gd` for debugging                                                                                                      |
| `useResizeHandler` | `Boolean`                    | `false`                                           | When true, adds a call to `Plotly.Plot.resize()` as a `window.resize` event handler                                                                    |

**Refs**: a `ref` attached to `<Plot>` resolves to the rendered `<div>` element (the plotly graph div), so you can call low-level plotly.js APIs against it directly (e.g. `Plotly.toImage(ref.current)`).

**TypeScript**: this package ships its own declaration files. Trace and layout shapes are typed as `unknown` since the wrapper does not bind to a specific plotly.js type surface; consumers wanting tighter typing on the `data` / `layout` props can re-declare them locally.

**Note**: To make a plot responsive, i.e. to fill its containing element and resize when the window is resized, use `style` or `className` to set the dimensions of the element (i.e. using `width: 100%; height: 100%` or some similar values) and set `useResizeHandler` to `true` while setting `layout.autosize` to `true` and leaving `layout.height` and `layout.width` undefined. A short example is in the [Responsive plot](#responsive-plot) section below. See also the [responsive layout reference](https://plotly.com/javascript/responsive-fluid-layout/).

#### Callback signature: `Function(figure, graphDiv)`

The `onInitialized`, `onUpdate` and `onPurge` props are all functions which will be called with two arguments: `figure` and `graphDiv`.

- `figure` is a serializable object with three keys corresponding to input props: `data`, `layout` and `frames`.
  - As mentioned above, for the time being, this component may _mutate_ its `layout` and `data` props in response to user input, going against React rules. This behaviour will change in the near future once https://github.com/plotly/plotly.js/issues/2389 is completed.
- `graphDiv` is a reference to the (unserializable) DOM node into which the figure was rendered.

### Event handler props

Event handlers for specific [`plotly.js` events](https://plotly.com/javascript/plotlyjs-events/) may be attached through the following props:

| Prop                       | Type       | Plotly Event                    |
| -------------------------- | ---------- | ------------------------------- |
| `onAfterExport`            | `Function` | `plotly_afterexport`            |
| `onAfterPlot`              | `Function` | `plotly_afterplot`              |
| `onAnimated`               | `Function` | `plotly_animated`               |
| `onAnimating`              | `Function` | `plotly_animating`              |
| `onAnimatingFrame`         | `Function` | `plotly_animatingframe`         |
| `onAnimationInterrupted`   | `Function` | `plotly_animationinterrupted`   |
| `onAutoSize`               | `Function` | `plotly_autosize`               |
| `onBeforeExport`           | `Function` | `plotly_beforeexport`           |
| `onBeforeHover`            | `Function` | `plotly_beforehover`            |
| `onBeforePlot`             | `Function` | `plotly_beforeplot`             |
| `onButtonClicked`          | `Function` | `plotly_buttonclicked`          |
| `onClick`                  | `Function` | `plotly_click`                  |
| `onClickAnnotation`        | `Function` | `plotly_clickannotation`        |
| `onDeselect`               | `Function` | `plotly_deselect`               |
| `onDoubleClick`            | `Function` | `plotly_doubleclick`            |
| `onFramework`              | `Function` | `plotly_framework`              |
| `onHover`                  | `Function` | `plotly_hover`                  |
| `onIcicleClick`            | `Function` | `plotly_icicleclick`            |
| `onLegendClick`            | `Function` | `plotly_legendclick`            |
| `onLegendDoubleClick`      | `Function` | `plotly_legenddoubleclick`      |
| `onLegendTitleClick`       | `Function` | `plotly_legendtitleclick`       |
| `onLegendTitleDoubleClick` | `Function` | `plotly_legendtitledoubleclick` |
| `onRelayout`               | `Function` | `plotly_relayout`               |
| `onRelayouting`            | `Function` | `plotly_relayouting`            |
| `onRestyle`                | `Function` | `plotly_restyle`                |
| `onRedraw`                 | `Function` | `plotly_redraw`                 |
| `onSelected`               | `Function` | `plotly_selected`               |
| `onSelecting`              | `Function` | `plotly_selecting`              |
| `onSliderChange`           | `Function` | `plotly_sliderchange`           |
| `onSliderEnd`              | `Function` | `plotly_sliderend`              |
| `onSliderStart`            | `Function` | `plotly_sliderstart`            |
| `onSunburstClick`          | `Function` | `plotly_sunburstclick`          |
| `onTransitioned`           | `Function` | `plotly_transitioned`           |
| `onTransitioning`          | `Function` | `plotly_transitioning`          |
| `onTransitionInterrupted`  | `Function` | `plotly_transitioninterrupted`  |
| `onTreemapClick`           | `Function` | `plotly_treemapclick`           |
| `onUnhover`                | `Function` | `plotly_unhover`                |
| `onWebGlContextLost`       | `Function` | `plotly_webglcontextlost`       |

To receive `onClick` or `onHover` for positions that are not over a trace, set
`clickanywhere` or `hoveranywhere` in your `layout`. These are layout attributes
rather than distinct events: the ordinary `plotly_click` / `plotly_hover` fire
with an empty `points` array, plus `xvals` / `yvals` — arrays of the cursor
position in data space, one entry per axis.

```javascript
<Plot
  data={data}
  layout={{clickanywhere: true}}
  onClick={(e) => console.log(e.points, e.xvals, e.yvals)}
/>
```

## Examples

### Responsive plot

To make the plot fill its container and resize with the window, leave the layout's `width`/`height` unset, enable `autosize`, and turn on `useResizeHandler`. Size the wrapper `<div>` with `style` or `className`:

```javascript
<Plot
  data={[{x: [1, 2, 3], y: [2, 6, 3], type: 'scatter'}]}
  layout={{autosize: true, title: {text: 'Responsive'}}}
  style={{width: '100%', height: '100%'}}
  useResizeHandler
/>
```

### Event handlers

All [plotly.js events](https://plotly.com/javascript/plotlyjs-events/) are surfaced as `on<EventName>` props (see the [Event handler props](#event-handler-props) table). Each handler receives the raw plotly.js event payload:

```javascript
<Plot
  data={[{x: [1, 2, 3], y: [2, 6, 3], type: 'scatter', mode: 'markers'}]}
  layout={{title: {text: 'Click me'}}}
  onClick={(event) => {
    const point = event.points[0];
    console.log(`clicked (${point.x}, ${point.y})`);
  }}
  onRelayout={(event) => {
    if (event['xaxis.range[0]']) {
      console.log('user zoomed to', event['xaxis.range[0]'], event['xaxis.range[1]']);
    }
  }}
/>
```

### TypeScript

The package ships its own declaration files.

```typescript
import Plot, {PlotParams, Figure} from 'react-plotly.js';

const onUpdate = (figure: Figure, gd: HTMLElement) => {
  console.log('figure data length:', figure.data.length, 'gd id:', gd.id);
};

const params: PlotParams = {
  data: [{x: [1, 2, 3], y: [2, 6, 3], type: 'scatter'}],
  layout: {title: {text: 'Typed'}},
  onUpdate,
};

export const App = () => <Plot {...params} />;
```

### Grabbing the graph div via `ref`

A `ref` attached to `<Plot>` resolves to the rendered plotly graph div. Use it to call low-level plotly.js APIs:

```javascript
import {useRef} from 'react';
import Plot from 'react-plotly.js';
import Plotly from 'plotly.js';

function ExportButton() {
  const ref = useRef(null);
  const exportPng = async () => {
    const dataUrl = await Plotly.toImage(ref.current, {format: 'png'});
    console.log(dataUrl);
  };
  return (
    <>
      <Plot ref={ref} data={[{x: [1, 2, 3], y: [2, 6, 3], type: 'scatter'}]} layout={{}} />
      <button onClick={exportPng}>Export PNG</button>
    </>
  );
}
```

## Customizing the `plotly.js` bundle

By default, the `Plot` component exported by this library loads a precompiled version of all of `plotly.js`, so `plotly.js` must be installed as a peer dependency. This bundle is around 6Mb unminified, and minifies to just over 2Mb.

If you do not wish to use this version of `plotly.js`, e.g. if you want to use a [different precompiled bundle](https://github.com/plotly/plotly.js/blob/master/dist/README.md#partial-bundles) or if your wish to [assemble you own customized bundle](https://github.com/plotly/plotly.js/blob/master/CUSTOM_BUNDLE.md), or if you wish to load `plotly.js` [from a CDN](https://github.com/plotly/plotly.js#use-the-plotlyjs-cdn-hosted-by-fastly), you can skip the installation of as a peer dependency (and ignore the resulting warning) and use the `createPlotComponent` method to get a `Plot` component, instead of importing it:

```javascript
// simplest method: uses precompiled complete bundle from `plotly.js`
import Plot from 'react-plotly.js';

// customizable method: use your own `Plotly` object
import createPlotlyComponent from 'react-plotly.js/factory';
const Plot = createPlotlyComponent(Plotly);
```

## Loading from a `<script>` tag

For quick one-off demos in JSFiddle or similar environments, you can load the component directly as a script tag. We don't host the bundle ourselves, so don't rely on this in production, but you can pull it from a CDN such as [unpkg](https://unpkg.com) or [jsdelivr](https://www.jsdelivr.com):

```html
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://cdn.plot.ly/plotly-3.6.0.min.js"></script>
<script src="https://unpkg.com/react-plotly.js@latest/dist/create-plotly-component.min.js"></script>
```

React is pinned to 18 here because React 19 stopped shipping UMD builds; consumers wanting React 19 should load it via [importmap](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) or use a bundler.

The factory is exposed as the global `createPlotlyComponent`. Build the component and mount it:

```javascript
const Plot = createPlotlyComponent(Plotly);
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  React.createElement(Plot, {
    data: [{x: [1, 2, 3], y: [2, 1, 3]}],
  })
);
```

## Development

To get started:

```bash
$ npm install
```

To build the published artifacts (`dist/index.{mjs,cjs}`, `dist/factory.{mjs,cjs}`, the UMD bundle, and the declaration files) via [tsup](https://tsup.egoist.dev/):

```bash
$ npm run build
```

To run lint + typecheck + jest:

```bash
$ npm run test
```

To watch source files and rebuild on change:

```bash
$ npm run watch
```

Releases are cut from `main` per the steps in [`RELEASE.md`](./RELEASE.md).

## License

&copy; 2017-2026 Plotly, Inc. MIT License.
