Photo by Toa Heftiba on Unsplash

Fetching Document Updates to Plugin UI

Creating an immediate plugin-document-plugin loop based on where the user focuses.

3 min readApr 5, 2020

--

One of the most confusing parts of writing a Figma Plugin is differentiating between the code.ts and ui.ts (or the JS script within the ui.html file). The way I understand them is as follows:

  1. code.ts contains the code that is executed on the main Figma Document UI. It has access to the Plugin API as specified in the figma.d.ts file.
  2. ui.ts (or the JS script within the ui.html file) contains the code that is executed when the user interacts with the Plugin UI (rendered as an iFrame). It does not have access to the Plugin API.

In many cases, a plugin you are trying to create requires it to extract some information from the Document UI (e.g. current selection). It will then present this information to the user, who then makes some changes or decisions based on it (e.g. wanting to change the size of the selected rectangle). Once the user decides on the appropriate course of action, the plugin needs to tell the Document UI to execute it.

In order to facilitate this two-way communication, Figma designed a protocol similar to Events for its Plugin API. You can read all about it by going to the official documentation.

What I want to show you in this article is how to use this protocol to allow the Plugin UI to be aware of changes made in the Document UI without having to re-instantiate itself. In other words, I hope to show you how to establish an immediate plugin-document-plugin feedback loop using the above protocol.

Essentially, the trick is having the Plugin UI inform the Document UI when the focus is back on the former and then having the latter send an immediate response back. Take a look at the ui.html and code.ts files below:

ui.html
code.ts

What happens is that when you first launch the Plugin, the figma.showUI(__html__, uiOptions) is executed, which renders the Plugin UI. The focus is also automatically set to the Plugin UI.

When the user shifts focus out of the Plugin UI, nothing happens. However, when the user focuses back into the Plugin UI, it runs the window.onfocus code block, which contains a parent.postMessage call that sends a message back to the Document UI. Notice that instead of sending a simple data type, I decided to send an Object. This allows for the flexibility needed in more complex plugins should there be different types of back-and-forth communication between the Document and Plugin UIs.

When the Document receives the message from the Plugin UI, it runs the code block within figma.ui.onmessage. In this case, since the Plugin UI has sent a "focus" type of message, it increments the count variable and sends it back to the Plugin UI.

Finally, the Plugin UI, on receiving the reply from the Document UI, updates the HTML and shows the count as the number of times the user shifts focus out of itself. This is how the working prototype looks like:

A GIF showing the working prototype in Figma
Every time I click out of the Plugin UI and back in, the count increments by 1.

Extending this into a more complex communication mechanism only takes coming up with multiple types of messages which would take different ways of handling within the code.ts code block. Conversely, you may also introduce a type key for the message from the Document to the Plugin UI should you require the extra flexibility on the Plugin UI-side as well. Here is an example of how I used the above implementation to automatically change the suggested name in the plugin’s textbox:

When I switched from “Page 1” to “Copy of Page 1” and refocused on the plugin, the textbox automatically adapts to the new page selected.

And that is how you fetch updates from the Document UI to Plugin UI using the messaging protocol of the Figma Plugin API!

Note: If you want to see the source code, just click on the “Communication Snippet” GIF above.

--

--

Full-time developer, part-time designer, casual pianist and gamer. Currently coding the Future of Travel @amadeusapac