Edit in GitHubLog an issue

Quick Start - React: Make your first XD plugin with React

While there are many choices when it comes to picking a JavaScript framework to build an XD plugin, we want to cover one of the most popular frameworks, React, first.

Once you're done, you'll have a solid grasp of the steps to take when starting to create your own XD plugin with React.

Prerequisites#

  • Basic knowledge of HTML, CSS, JavaScript, and React
  • A text editor to write your code in (like VSCode, Sublime Text, Brackets, Atom, etc)
  • Quick Start tutorial
  • node and npm installed

Development Steps#

Info Complete code for this plugin can be found on GitHub.

0. Folder structure#

Note that we are going to use webpack to bundle JavaScript files for usage in XD and the yarn package manager to install dependencies. When you have the right structure, it will look like this:

Copied to your clipboard
1my-plugin-folder
2└── src
3 └── main.jsx
4 └── HelloForm.jsx
5 └── react-shim.js
6└── manifest.json
7└── package.json
8└── webpack.config.js

1. Install dependencies#

In order to correctly use React in XD, you will have to install dependencies correctly. Follow the steps below:

  1. List the required dependencies in package.json
Copied to your clipboard
1{
2 "name": "helllo_react_jsx",
3 "version": "1.0.0",
4 "main": "main.js",
5 "scripts": {
6 "watch": "nodemon -w src -e js,jsx,css -w webpack.config.js -x yarn build",
7 "build": "webpack --mode development"
8 },
9 "license": "none",
10 "private": true,
11 "devDependencies": {
12 "nodemon": "^1.18.7",
13 "webpack": "^4.16.4",
14 "webpack-cli": "^3.1.0"
15 },
16 "dependencies": {
17 "babel-core": "^6.26.3",
18 "babel-loader": "^7.1.5",
19 "babel-plugin-transform-react-jsx": "^6.24.1",
20 "css-loader": "^1.0.0",
21 "react": "^16.4.2",
22 "react-dom": "^16.4.2",
23 "style-loader": "^0.22.0",
24 "yarn": "^1.12.3"
25 }
26}
  1. List the webpack configurations in webpack.config.js
Copied to your clipboard
1module.exports = {
2 entry: "./src/main.jsx",
3 output: {
4 path: __dirname,
5 filename: "main.js",
6 libraryTarget: "commonjs2",
7 },
8 devtool: "none",
9 module: {
10 rules: [
11 {
12 test: /\.jsx?$/,
13 exclude: /node_modules/,
14 loader: "babel-loader",
15 options: {
16 plugins: ["transform-react-jsx"],
17 },
18 },
19 {
20 test: /\.css$/,
21 use: ["style-loader", "css-loader"],
22 },
23 ],
24 },
25 externals: {
26 scenegraph: "scenegraph",
27 },
28};

As per webpack's documentation,

The externals configuration option provides a way of excluding dependencies from the output bundles. Instead, the created bundle relies on that dependency to be present in the consumer's environment.

Note that, in this example, we are excluding the scenegraph API from the output bundles since this dependency is present in the XD environment.

  1. Install yarn, if needed
Copied to your clipboard
npm install -g yarn
  1. Install dependencies
Copied to your clipboard
yarn install

All dependencies are installed and we are good to go!

2. Create your main files#

Now, let's create your plugin files. Open your favorite text editor and create the following files and folders (we'll add code to them in later steps):

  • manifest.json is your plugin’s manifest. This file includes information about the plugin, such as its name, the menu item(s) it adds to XD, and so on. Learn about the manifest here.

  • src is your plugin's folder that contains all JavaScript files that are going to be compiled

    • main.jsx is the main file for the plugin
    • HelloForm.jsx is the file that contains the only React component we are going to use. Note that you can have multiple .jsx files if needed
    • react-shim.js is a JavaScript file that helps React run smoothly in XD's environment. Further details to follow in a later section

3. Edit your plugin’s manifest#

In the previous step, you created a file named manifest.json. Open that file and paste in this JSON object:

Copied to your clipboard
1{
2 "id": "QUICKSTART_REACT",
3 "name": "Quick Start - React",
4 "version": "1.0.0",
5 "description": "Description of your plugin.",
6 "summary": "Summary of your plugin",
7 "languages": ["en"],
8 "author": "Your Name",
9 "helpUrl": "https://mywebsite.com/help",
10 "host": {
11 "app": "XD",
12 "minVersion": "13.0"
13 },
14 "uiEntryPoints": [
15 {
16 "type": "menu",
17 "label": "Quick Start - React",
18 "commandId": "main"
19 }
20 ]
21}

Be sure to replace the id value with the unique plugin ID you get from the Adobe Developer Console.

Copied to your clipboard
"id": "1234ABCD",

Info Make sure to read Quick Start tutorial to learn how to get your unique plugin ID from the Adobe Developer Console.

If you're curious about what each entry in the manifest means, see the manifest documentation, where you can also learn about all manifest requirements for a plugin to be published in the XD Plugin Manager.

The value of the commandId property may be any string; in this case, it's main. In the next section, we will see how this string is associated with the code for our plugin.

4. Create your plugin’s code#

Next, we need to create the JavaScript code for our plugin. As noted in the Quick Start tutorial, the code lives in a file named main.js. This file will be automatically created when Webpack compiles all JavaScript files in your src folder.

In this tutorial, the src folder will contain the following:

Copied to your clipboard
1src
2└── main.jsx
3└── HelloForm.jsx
4└── react-shim.js

Now, lets start writing code in these JavaScript files.

First of all, as noted earlier, we need react-shim.js file to make React run without any issue in the XD environment. Paste this code into react-shim.js:

Copied to your clipboard
1if (window.setTimeout == null) {
2 window.setTimeout = function (fn) {
3 fn();
4 };
5}
6
7if (window.clearTimeout == null) {
8 window.clearTimeout = function () {};
9}
10
11if (window.cancelAnimationFrame == null) {
12 window.cancelAnimationFrame = function () {};
13}
14if (window.requestAnimationFrame == null) {
15 window.requestAnimationFrame = function () {
16 console.log("requestAnimationFrame is not supported yet");
17 };
18}
19if (window.HTMLIFrameElement == null) {
20 window.HTMLIFrameElement = class HTMLIFrameElement {};
21}

Since XD currently does not currently support cancelAnimationFrame, requestAnimationFrame, and HTMLIFrameElement, we create these empty functions and classes to prevent your plugin from crashing.

As of XD 16, setTimeout and clearTimeout are supported in the XD plugin API, but are still included in the shim for compatibility with older versions of XD.

Next, let's create a React component. Paste the following code in HelloForm.jsx:

Copied to your clipboard
1// [1]
2const React = require("react");
3// [2]
4const { Text, Color } = require("scenegraph");
5
6// [3]
7class HelloForm extends React.Component {
8 // [4]
9 constructor(props) {
10 super(props);
11 this.state = { name: "" }; // [5]
12
13 // [6]
14 this.onInputChange = (e) => {
15 this.setState({ name: e.target.value });
16 };
17
18 // [7]
19 this.onDoneClick = (e) => {
20 // [8]
21 const selection = this.props.selection;
22 // [9]
23 const newText = new Text();
24 newText.text = this.state.name;
25 // [10]
26 newText.styleRanges = [
27 {
28 length: newText.text.length,
29 fill: new Color("#00F"),
30 fontSize: 50,
31 },
32 ];
33
34 // [11]
35 selection.insertionParent.addChild(newText);
36 // [12]
37 newText.moveInParentCoordinates(100, 100);
38 // [13]
39 props.dialog.close();
40 };
41 }
42
43 // [14]
44 render() {
45 return (
46 <form style={{ width: 300 }} onSubmit={this.onDoneClick}>
47 <h1>React with JSX Components</h1>
48 <label>
49 <span>What is your name?</span>
50 <input onChange={this.onInputChange} />
51 </label>
52 <p>{`Hello ${this.state.name}`}</p>
53 <footer>
54 <button type="submit" uxp-variant="cta">
55 Done
56 </button>
57 </footer>
58 </form>
59 );
60 }
61}
62
63module.exports = HelloForm;

This code does the following:

  1. Gets reference to react module installed in an earlier step
  2. Gets references to the Text and Color classes from XD’s scenegraph module. There are several different API modules you can load using require().
  3. Creates a react component called HelloForm
  4. Since you are going to initialize state and bind methods, implements a constructor for this React component and calls super(props) to use props passed down from the parent
  5. Initializes a state property called name with an empty string
  6. onInputChange method sets the name state with the string value passed from the input field
  7. onDoneClick is triggered after the submission happens and manipulates XD objects
  8. Creates a reference to selection passed down as a prop
  9. Creates a Text instance and sets the text value as the input stored in the name state
  10. Styles the text. More info on styling text can be found in how-to-style-text tutorial
  11. addChild method inserts the created text into the ideal insertion point determined by the insertionParent property of the selection object
  12. Moves the added text 100 pixels from the top and 100 pixels from the left of the insertion point
  13. Closes the dialog
  14. Renders the component. Note that there is an input field to accept user's input and a button for the submission of the input

Lastly, let's create the main jsx file, main.jsx. Paste the following code into main.jsx:

Copied to your clipboard
1// [1]
2const reactShim = require("./react-shim");
3// [2]
4const React = require("react");
5const ReactDOM = require("react-dom");
6// [3]
7const App = require("./HelloForm.jsx");
8
9function main(selection) {
10 let dialog;
11
12 function getDialog() {
13 if (dialog == null) {
14 // [4]
15 dialog = document.createElement("dialog");
16 // [5]
17 ReactDOM.render(<App dialog={dialog} selection={selection} />, dialog);
18 }
19 return dialog;
20 }
21
22 // [6]
23 return document.body.appendChild(getDialog()).showModal();
24}
25
26// [7]
27module.exports = {
28 commands: {
29 main,
30 },
31};

This code does the following:

  1. Loads react-shim.js to make React run in the XD environment
  2. Gets reference to react and react-dom modules installed earlier in the steps
  3. Imports our HelloForm component
  4. Creates a dialog element in the document
  5. Renders the imported HelloForm component and passes dialog and selection objects as props. Note that the dialog is reused, so it gets rendered only once.
  6. Loads the modal inside the XD document
  7. Exports an object, with a commands property. The value of commands is an object which associates the JavaScript handler function (main) with your manifest's commandId property. The command ID property name (here, main) must match the commandId value declared in your manifest exactly.

5. Compile the code#

Developement - Run yarn watch to compile the code and watch for changes. This process will create the main.js file to be read by Adobe XD.

Production - Run yarn build to build the final version of your plugin.

5. Run your plugin#

So you’ve written a plugin using React! How do we run it?

If you haven’t already done so, launch XD and open a new document. Then navigate to the Plugins > Quick Start - React menu item.

Alternatively, if XD was already open, select Plugins > Development > Reload Plugins.

XD dialog drops down

Congratulations! You’ve built your first plugin using React!

Was this helpful?
Copyright © 2021 Adobe. All rights reserved.