Six Steps to Creating Your First XD Plugin Using React

A step by step guide to creating a panel plugin for Adobe XD using React, created at the Adobe Fund for Design Plugin Accelerator

Matt Holcombe
Nov 27 · 10 min read

“Today’s guest post is by Matt Holcombe, a Co-Founder and CTO of Pair, an NPM Module for product teams who review and critique front-end design. This summer, Pair took part in the Adobe Fund for Design Plugin Accelerator (cohort 1). The Plugin Accelerator was a three month in-house program where Pair had the opportunity to work 1:1 with the Adobe XD team.

In this article, Matt and Jason provide a solid panel plugin example (built with React) that populates shapes with random images from Unsplash, and exports .png and .svg files.

Editor’s Note: We’ve had several requests for plugins which export React code from Adobe XD. Please note, this article covers writing XD plugins using React.”

— Erin Finnegan, Community Engineer, Creative Cloud

This article is intended for JavaScript developers familiar with NPM modules, React, and who are more or less familiar with Adobe XD. If you’re a beginner unfamiliar with React and NPM, please read this beginner-friendly tutorial instead.

Adobe XD plugins are created using JavaScript technologies. You can pick from a myriad of frameworks to author in, as long as the end code interpreted by XD is standard JavaScript. In this article, we will walk you through authoring a plugin with the popular React framework using JSX, in conjunction with webpack to transform and bundle the source into JavaScript consumable by XD.

A little background information

ES5 is fully supported, and some of ES6 at the time of writing this article (version 21). Don’t expect all your Node packages to work out of the box though; XD’s plugin sandbox supports NPM Modules using only the core JavaScript APIs (eg. no file system access or external process launching).

On that note, the XD plugin environment isn’t a browser. Instead there’s a technology called UXP, (short for Unified Extensibility Platform), developed by Adobe that powers the plugin’s code. It aims to map closely to web standards for HTML, CSS, and JavaScript — where possible. For example, fetch and WebSocket in XD behave pretty much as expected. UXP is, however, not all encompassing as mentioned previously, supporting a limited number of elements and APIs. Plus only a subset of CSS is available to further style UI elements. (Editor’s Note: The file system access limitation is a constraint of Adobe XD, and not UXP as a whole. Also note that UXP continues to evolve; keep watching this blog for updates.)

The two fundamental resources that I exploited extensively during my time plugin developing this summer were the Adobe XD Platform Community Forums and the Adobe XD API References. The forum’s posts are never ignored or neglected; you can expect a response from a vetted Adobe employee or another knowledgeable forum member within a day’s time. The API documentation is pretty comprehensive and verbose, even housing several quick start tutorials for different plugin types and development strategies, plus many more miscellaneous technical references to check out.

XD Plugin Flows: Panel left, Modal right

Step 0: Modal or Panel?

There are two kinds of plugin flows supported by Adobe XD: dialog (or modal) and panel. Dialog plugins drop down from the top of the application and block further user interaction until dismissed. Think of the “Save File As…” dialog from the OS. They have their place, but not all tasks benefit from the need to interrupt workflow. Panel plugins fill that role, integrating nicely into a dedicated area off to the side (the plugins panel). Think of a color wheel, or a histogram / spectrum thingy monitoring document changes, affecting the plugin’s UI. A histogram presents relevant UI back to the user based on accurate data coming from the SceneGraph (a data structure representing a hierarchical tree of nodes). That’s also the ticket to manipulating the document as the plugin’s controls are pressed, tweaked, and pushed in real-time. The plugin effectively becomes another tool to use, embedded right into Adobe XD’s native application.

In fact, the UXP engine renders true application UI elements from the plugin’s HTML + CSS + JavaScript. I’m getting way ahead of myself here, so let’s just go with the panel type plugin and we’ll get to the interesting stuff in a bit.

Step 1: Setting up your Project

Getting up and running is a fairly simple process. The first thing on the list is getting a hold of Adobe XD v21 or greater. Additionally, you will need:

  • A JavaScript friendly IDE such as VSCode, WebStorm, even Atom or Notepad++ will suffice.
  • A repository management tool like git, used behind the scenes by the build tools. You’ll also need it to pull down the example code, and push it back up to your own repo if you wish.
  • Some JavaScript software to install sources from a remote registry, and then build JS from node packages: node with npm and yarn.

Once you have Adobe XD and the required software installed, the next step is locating your local plugin development folder. This can be found easily by opening the Adobe XD application, navigating to the main menu, then selecting the Plugins menu item. From there, choose Development -> Show Develop Folder.

Location to the XD develop folder

Step 2: Project Installation

For this demo, there’s already a simple project I created over on GitHub. Go ahead and git clone https://github.com/de-ai/xd-blog-expo.git /your/plugin/folder. Once the project has been pulled down, execute yarn install within the project’s root directory to pull in the necessary dependencies. Keep a file watcher going to recompile the project automatically, by typing npm run watch (or yarn watch) in the terminal also from the project’s root folder.

Downloading and installing a project

Step 3: How to Debug your Project

Adobe XD provides a developer output console, where runtime errors and console.log() statements are logged. It can be opened via the menu Plugins -> Development -> Developer Console.

XD’s Developer Console floating window

For your convenience, plugins in develop mode can be reloaded quickly to reflect their latest changes. From the menu: Plugins -> Development -> Reload plugins or by keyboard shortcut if you’re into that kind of thing: Shift+Cmd+R (macOS) / Ctrl+Shift+R (Windows).

Step 4: Specific Adobe XD Resources

A required configuration file named manifest.json is first up in the sample project. It contains some definitions and metadata pertaining to a plugin. Read this section of the documentation for a detailed explanation about the file specification.

The webpack.config.js file included is pretty standard, the only bit that deserves attention is the externals entry. This is where imported native XD modules are listed. The webpacked code will use these from the installed XD binary instead of bundling them with the build. So the plugin user’s XD application will include these at runtime on their local machine.

Editor’s Note: The react-shim.js below is no longer required as of XD 24.

With the configs squared away, let’s investigate the project’s src folder. The plugin’s starting point is main.jsx (defined in webpack’s config). A pretty standard looking entry point, besides the first line that requires the helper file react-shim.js as shown below:

react-shim.js helper (not required in XD 24)

Simply put, the shim provides XD’s JavaScript engine with some window functions if they are not defined. It also assigns the window’s iframe element to the HTMLIFrameElement built into XD.

Next, the PanelController component mounts App and holds three functions implemented by the panel plugin specification: show(), hide(), and update().

PanelController Component

After the plugin successfully loads, show() is called, where the App instance is attached to a generated root div element, then rendered in typical React fashion. Afterwards, whenever the SceneGraph changes, the update() function is called, which calls documentStateChanged() on App, passing along the current selection with the SceneGraph root node. When the plugin unloads, hide() is invoked and App is then unmounted. For the detailed plugin lifecycle explanation, check out this overview on the XD Platform site.

Step 5: Adding UI Components

The App displays three inner components within the plugin panel area and handles a couple of their actions.

The App Component

The most important (and exciting) XD specific happening here is the editDocument function. The first parameter is the undo label (what the plugin user sees under the menu Edit -> Undo). The second is a function passing the current selection + SceneGraph root node. It’s extremely important to note that this is the only place where document changes can be made from code. So in this instance of editDocument() in App, a bounding rectangle is calculated from the union of one or more selected items on the canvas. The viewport (canvas viewing area) is then panned and zoomed to those bounds.

To reiterate, the only way to make edits on the SceneGraph is by using editDocument(), and it can only be invoked by a user interaction like a button click or input change originating from the plugin’s UI. If the action is asynchronous, such as fetching remote data, the operation must use a Promise or the async / await keywords in order to “pause” the plugin until the action completes.

We’ll skip the two ancillary section components declared in App, as they are made up of the usual standard React code. Have a look at them on your own if you wish, otherwise let’s move on to MainContent.jsx.

MainContent Component

Above, the UI is composed of three buttons demonstrating some plugin capabilities. Their disabled attributes are set based on the current selection, and a uxp-variant attribute provides basic built-in styling loosely adhering to XD’s native UI. A list of UXP variants can be found here.

The first button passes its click handler up to App to pan and zoom the viewport, which we already covered.

The second button fills a shape type object with a random JPEG image provided by Unsplash’s Dev API. Bear in mind, this API key provided is just a demo app with only 50 calls / hour, so please don’t abuse it. If you feel so inclined, create your own app and use that key in its place. Within the handler’s editDocument(), a first async call is made, which returns a JSON object describing the image. The description entry is used to rename the layer, one of the source URLs is also grabbed for use on the following fetch call. Taking the entry’s full size image URL through the second and last async fetch call, the response is converted from a data buffer to a binary string. Finally the selected node gets filled with the base-64 encoded representation of that binary image data.

Lastly, the third button exports an image file (PNG or SVG), depending on fill type for each of the selected canvas layers. An “Open File” dialog is presented courtesy of the file system to choose a location to write the rendition(s). After confirmed, a file handler is created at that path with a name generated from the layer’s name plus it’s guid (a UUID) properties. A set of export options are defined, createRendition() is called, ultimately writing the file contents and closing the handle.

Final Step: Packaging your Plugin

Creating a distributable version of your React plugin is a fairly simple process. First execute yarn build within the project’s root folder. The bundled JS is written by webpack to main.js, located off the project’s root folder. Files imported in the source by using the require statement will also be copied and renamed with a hash to this location (if you haven’t modified webpack.config.js). You’ll first have to create a standard ZIP file adding main.js, manifest.json, the images folder, plus any other assets placed on the root folder by webpack just mentioned previously. Then change the file extension from .zip to .xdx, so Adobe XD recognises it as a plugin package. Double clicking on the renamed .xdx file will install the plugin in the conventional plugin folder so long as the manifest checks out.

Plugin installation was a success!

To publicly distribute the plugin to users through Adobe’s in-app Plugin Manager requires a few more steps:

  • Head over to the Adobe I/O Console, and create a new application if you haven’t done so already.
  • Upload the packaged XDX file to kick off the submission process. After the manifest.json passes validation, you’ll be prompted for some additional info, namely some product text descriptions, additional icons, plus a screenshot for the Plugin Manager storefront.
  • Lastly, provide any review notes such as test account logins or other specific instructions needed for a complete review.

If everything checks out, you’ll be able to submit, and the Creative Cloud Integrations team will start the review process. After ten business days or less, the review team should get back to you with a response whether or not the submission was approved or rejected (with steps to remedy if need be). For more detailed publication steps, follow this guide. (For tips on avoiding a rejection check out this article.)

Text and metadata employed by the Plugin Manager at console.adobe.io

Conclusion

As you can see, creating a React plugin for Adobe XD is both simple and straight forward development. I hope this demonstration sparks your interest to create your own XD plugin(s) for your own use, but also to share with the rest of the XD community.

Here’s a list of resources mentioned you may find useful:


Sign up for Pair, an NPM Module for product teams to review and approve design by going to www.pairurl.com. You can also follow us on Instagram or Twitter.


For more stories like this, subscribe to the Creative Cloud Developer Newsletter.

Adobe Tech Blog

News, updates, and thoughts related to Adobe, developers, and technology.

Thanks to Erin Finnegan and Ash Ryan Arnwine

Matt Holcombe

Written by

Adobe Tech Blog

News, updates, and thoughts related to Adobe, developers, and technology.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade