Unlayer Examples
Documentation

React Custom Tool

In this example, we will create a custom tool with React and a custom property editor with React.

Each custom tool is built in its own custom.js file which is then passed to unlayer.init. In this case, we'll need our custom.js file to use React.

1. Importing React

The first step to create a custom tool using React is to make sure we can access React in our bundle.

We recommend reusing Unlayer's React for better performance and avoiding version conflicts. We have the following libraries available globally:

  • unlayer.React
  • unlayer.ReactDOM

If you still need a different version of React, you can bundle it with your custom.js code.

You can access Unlayer's React by calling window.unlayer.React.

2. Webpack Configuration

If you are using a bundler like webpackto bundle your custom.js file, then you can add this to your webpack.config.jsfile:

externals: {
  'react': 'window.unlayer.React',
  'react-dom': 'window.unlayer.ReactDOM'
}

Once this is added, you can import React in your custom.js file just like you would do it normally.

import React, { Component } from 'react';

3. Register your Tool

We'll need to create a custom.js file that includes the JavaScript to create our custom tool. Inside your custom tool script, you can use JSX for the viewer and exporter components.

If you want to import other components into the custom tool code, you can add JSX to the Unlayer’s viewer component.

For exporters, make sure to convert JSX to string using ReactDOMServer.renderToStaticMarkup(). Here is the code example for the same:

custom.js

import * as ReactDOMServer from 'react-dom/server';
const React = window.unlayer.React;

const Viewer = () => {
  return <div>I am a custom tool.</div>;
};

unlayer.registerTool({
  name: 'my_tool',
  label: 'My Tool',
  icon: 'fa-smile',
  supportedDisplayModes: ['web', 'email'],
  options: {},
  values: {},
  renderer: {
    Viewer: Viewer, // this is your React component
    exporters: {
      web: function (values) {
        return ReactDOMServer.renderToStaticMarkup(<Viewer />);
      },
      email: function (values) {
        return ReactDOMServer.renderToStaticMarkup(<Viewer />);
      },
    },
    head: {
      css: function (values) {},
      js: function (values) {},
    },
  },
});

4. Bundle Your Custom Tool

Use a module bundler like Webpack or Vite to bundle your custom tool code into a standalone JavaScript file. Organize your tool code in a dedicated directory for maintainability.

5. Host the Custom Tool

After bundling, upload the output JavaScript file to a publicly accessible URL (e.g., https://yourdomain.com/custom-tool.js).

6. Add customJS to Builder Configuration

Use the customJS option inside the options property of the EmailEditor component to load your custom tool at runtime.

Preview

Here's a live running preview of our custom tool. Drag and drop the custom tool with a smiley face :)


React Tool with Custom Property Editor

Let's update our React custom tool to use a React custom property editor now. In this example, we will create a custom color picker.

You can also use our built-in property editors to save time, check out the full list of available built-in property editors.

1. Register your Tool

custom.js

import * as ReactDOMServer from 'react-dom/server';
const React = window.unlayer.React;

// Custom Color Picker
const MyColorPicker = (props) => {
  const { label, value, updateValue, data } = props;

  return (
    <div>
      <div>My React Color Picker</div>
      <input
        className="color-value"
        defaultValue={value}
        onChange={(e) => updateValue(e.target.value)}
      />
      <button className="red" onClick={() => updateValue('#f00')}>
        Red
      </button>
      <button className="green" onClick={() => updateValue('#0f0')}>
        Green
      </button>
      <button className="blue" onClick={() => updateValue('#00f')}>
        Blue
      </button>
    </div>
  );
};

unlayer.registerPropertyEditor({
  name: 'my_color_picker',
  Widget: MyColorPicker,
});

// Custom Tool Viewer
const Viewer = ({ values }) => {
  return <div style={{ color: values.textColor }}>I am a custom tool.</div>;
};

unlayer.registerTool({
  name: 'my_tool',
  label: 'My Tool',
  icon: 'fa-smile',
  supportedDisplayModes: ['web', 'email'],
  options: {
    default: {
      title: null,
    },
    text: {
      title: 'Text',
      position: 1,
      options: {
        textColor: {
          label: 'Color',
          defaultValue: '#ff0000',
          widget: 'my_color_picker',
        },
      },
    },
  },
  values: {},
  renderer: {
    Viewer: Viewer,
    exporters: {
      web: function (values) {
        return ReactDOMServer.renderToStaticMarkup(<Viewer values={values} />);
      },
      email: function (values) {
        return ReactDOMServer.renderToStaticMarkup(<Viewer values={values} />);
      },
    },
    head: {
      css: function (values) {},
      js: function (values) {},
    },
  },
});

2. Bundle Your Custom Tool

Use a module bundler like Webpack or Vite to bundle your custom tool code into a standalone JavaScript file. Organize your tool code in a dedicated directory for maintainability.

3. Host the Custom Tool

After bundling, upload the output JavaScript file to a publicly accessible URL (e.g., https://yourdomain.com/custom-tool.js).

4. Add customJS to Builder Configuration

Use the customJS option in the EmailEditor component to load your custom tool at runtime.

Preview

Here's a live running preview of our custom tool with built-in editor. Drag and drop the custom tool with a smiley face, and then select it on the canvas to play with the color picker.