Skip to content

Instantly share code, notes, and snippets.

@donfour
Last active December 15, 2023 02:12
Show Gist options
  • Save donfour/82193ab0c138afcc8c840c7a79474db4 to your computer and use it in GitHub Desktop.
Save donfour/82193ab0c138afcc8c840c7a79474db4 to your computer and use it in GitHub Desktop.
Sample Editor.js plugin in React

Intro

This gist contains a util function I wrote for creating Editor.js plugins in React. The sample plugin is taken from this Editor.js tutorial.

Context

As Editor.js current does not support React officially (See this issue), a lot of people are facing issues when trying to create an Editor.js plugin in React.

A common workaround is to:

  1. Create a div element in the constructor, and save it as a property:
constructor() {
  this._container = document.createElement("div");
}
  1. Render your React component to the div element by:
ReactDOM.render(
  createElement(<MyComponent/>, {
    /* props */
  }),
  this._container
);

As this pattern is used so much, I extracted out this logic into a util function createEditorJsPlugin. Hope it's useful!

import EditorJs from "react-editor-js";
import SimpleImage from "./SimpleImage";
const App = () => {
return (
<EditorJs
tools={{
simpleImage: SimpleImage,
}}
/>
)
};
export default App;
import { ChangeEventHandler, FunctionComponent } from "react";
import { createEditorJsPlugin, EditorJsPluginProps } from "./util";
type Props = {
url: string;
};
const SimpleImage: FunctionComponent<Props & EditorJsPluginProps<Props>> = (
props
) => {
const { dispatchData, url } = props;
const handleTextChange: ChangeEventHandler<HTMLInputElement> = (e) => {
dispatchData({ url: e.target.value });
};
return <input value={url} onChange={handleTextChange} />;
};
export default createEditorJsPlugin<Props>({
toolbox: {
title: "Image",
icon:
'<svg width="17" height="15" viewBox="0 0 336 276" xmlns="http://www.w3.org/2000/svg"><path d="M291 150V79c0-19-15-34-34-34H79c-19 0-34 15-34 34v42l67-44 81 72 56-29 42 30zm0 52l-43-30-56 30-81-67-66 39v23c0 19 15 34 34 34h178c17 0 31-13 34-29zM79 0h178c44 0 79 35 79 79v118c0 44-35 79-79 79H79c-44 0-79-35-79-79V79C0 35 35 0 79 0z"/></svg>',
},
initialData: { url: "" },
component: SimpleImage,
});
import { FunctionComponent, createElement } from "react";
import ReactDOM from "react-dom";
type CreateEditorJsPluginOptions<T> = {
toolbox: {
title: string;
icon: string;
};
initialData: T;
component: FunctionComponent<EditorJsPluginProps<T>>;
};
export type EditorJsPluginProps<T> = {
dispatchData: DispatchDataFunc<T>;
};
type DispatchDataFunc<T> = (data: T) => void;
export function createEditorJsPlugin<T>(
options: CreateEditorJsPluginOptions<T>
) {
const {
toolbox: { title, icon },
initialData,
component,
} = options;
return class {
static get toolbox() {
return {
title,
icon,
};
}
_container: HTMLDivElement;
_data: T;
constructor() {
this._container = document.createElement("div");
this._data = initialData;
}
render() {
this._renderContainer();
return this._container;
}
save() {
return {
...this._data,
};
}
// helper functions
_dispatchData: DispatchDataFunc<T> = (data) => {
this._data = data;
this._renderContainer();
};
_renderContainer() {
ReactDOM.render(
createElement(component, {
dispatchData: this._dispatchData,
...this._data,
}),
this._container
);
}
};
}
@husainasfak
Copy link

ReactDOM.render is deprecated since React 18.0.0. How to use this in react 18

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment