Hi there! Welcome to part three of the Build your first plugin series. In this video, we are going to get our environment set up and ready for us to start building a Figma plugin. If you are entirely new to plugins and would like an overview of basic programming concepts, check out parts one and two before watching the rest of this video.
We'll be following Figma's plugin setup guide, so it'll be helpful to have it open as we go through this tutorial. Up next, we're going to install:
Visual Studio Code - the development environment we'll use to build our plugin
Node.js - a way for us to run JavaScript outside of the browser and use tools like npm
Typescript - a programming language built on top of Javascript
Figma's Typings file - provides assistance while using Figma's Plugin API
By the end of the setup guide, we'll have a sample plugin that opens a modal, asks the user for a number, and creates that many rectangles on the canvas.
Install Visual Studio Code
First, we need to install Visual Studio Code. If you already have it on your computer, you can skip to the next step. Otherwise, pause the video and go to code.visualstudio.com to download Visual Studio.
Once your download is complete, let's launch Visual Studio Code and take a look. VS Code may ask you for a few additional setup steps like choosing a theme and browsing language extensions. We don't need to worry about this for now, so you can click on Get Started in the top left corner to go to the welcome screen.
On the welcome screen, you'll see a Start menu where we can create a new file, open an existing file or run a specific command. Let's create a new file to get a better look at our editor.
VS Code will open a new tab. This is the text editor where we'll do a majority of our work when we start writing code.
To the left, you'll see a sidebar with a few different icons.
Lets click on the first icon - it looks like two pieces of paper on top of each other. This is our Explorer. From here we can open code folders and view the structure of those projects.
Visual Studio is an Integrated Development Environment, meaning it combines several commonly used developer tools into one convenient interface.
Underneath the Explorer are icons for Search, Source Control, Run and Debug, and Extensions. We won't be using these IDE features, but feel free to explore if you want to continue familiarizing yourself with Visual Studio.
Install Node.js and npm
We're going to download the dependencies needed to build our plugin. A dependency is a library or piece of code needed in order for a different part of the project to work. For example, a car needs four wheels in order to run. Without one of the wheels, our car wouldn't get us anywhere. Or a house of cards. If we take one of the cards away, the whole thing collapses.
One way to manage these dependencies is through the use of a tool called 'npm' or Node Package Manager.
Originally, JavaScript was a language designed for web and could not run outside of a web browser. Node.js is an environment that allows us to do this.
Npm is the default package manager for Node.js. Npm is both a command-line tool and an online repository of open source Node.js projects. Instead of manually including dependencies into our project, npm makes it easy to install these dependencies using scripts.
For example, a library like TypeScript has hundreds of files and dependencies. If we were to include these dependencies manually, it would take us forever and it's likely that we'll make a mistake along the way. Instead, we can use a single npm script to install the entirety of TypeScript which saves us time and leaves less room for error.
In order to use npm, we first need to download Node.js. Go to nodejs.org and click on "Downloads."
Choose and download the installer for your operating system. Once the file is downloaded, open it to start the Node.js Setup Wizard.
Additional step (for Windows)
If you're on Windows, when you get to the part of the Node setup that asks about tools for native modules, check the box to Automatically install the necessary tools then hit Next. In the following screen, click Install. Once the installation is complete, hit Finish.
Verify npm installation
We can verify that node was properly installed by checking it in Visual Studio's built in terminal. A terminal is a text-based interface where we can do things like execute programs or type in commands to tell our computer to perform certain actions. Open up a new terminal window by clicking Terminal in the top menu and selecting New Terminal. Then, type node and hit enter. You'll see a line that will tell you which version of Node.js you've installed.
If you are not seeing this message, try restarting Visual Studio and running this command again.
Hit Ctrl-C twice to exit Node.
Install TypeScript
Now that you have Node installed, we have access to npm which allows us to install TypeScript. If you're a Windows user, make sure to start with the additional step below before continuing with the rest of your environment setup.
Additional step (for Windows)
On Windows, we need this additional setup step:
While in Visual Studio, hit Ctrl-Shift-P and in the search bar that pops up, type in "terminal select default profile" then select the matching option.
A new menu pops up listing our options for a default terminal profile. Select Command Prompt.
TypeScript install scripts
To use npm, we'll need to open up a new terminal window.
Find Terminal in the top level menu, then select New Terminal.
From here, we can install TypeScript using npm by typing this line of code in the command line and hitting Enter:
Windows: npm install -g typescript
Mac: sudo npm install -g typescript
You may be asked for a password once you run this script. Typically, this is the same password you use to log in to your computer. Keep in mind that once you start typing in your password, you may not see anything being typed out. Don't worry, the terminal is still reading your input.
If the installation is successful, you'll see something like this:
Verify TypeScript installation
To check that everything works, you can run this command to see the version of TypeScript you just installed:
tsc
Install the Figma desktop app
Awesome! You're almost ready to start building your first plugin. From here on out, Figma will need to read our code saved as a local file. To do this, we'll need the Figma desktop app which you can download from https://www.figma.com/downloads/
Now, select Plugins from the menu, then under Development select New plugin.
This will bring up the Create plugin modal. Since we're building this plugin for Figma only, we'll select Figma design. Let's name this "my-first-plugin", and hit Next.
You'll see three options for creating a new plugin - 'Empty', 'Run once' and 'With UI & browser APIs.' The sample plugin we're using requires an interface, so we'll create it with a UI & browser APIs. Hit Save as to save it anywhere on your disk. Moving forward, it might be helpful to create a dedicated folder for your plugins to make them easy to find later.
Open the code folder
Now that our sample plugin is saved, let's take a look at the underlying code. We can do this by opening up the folder in Visual Studio.
Go to File > Open Folder, then select the folder you saved when you created a new plugin.
A modal may pop up asking if you trust the authors of the files in this folder. Check the box and click "Yes, I trust the authors" to proceed.
Under Explorer, a new dropdown directory is available under the same name as the folder we opened. If you expand this, you'll notice that a few files already exist in our project.
Take a look at the manifest.json file. A manifest is a JSON file that specifies metadata about our project, like its name and version. In this sample plugin, we have a field in the manifest called editorType that is currently set to figma. As we mentioned earlier, this plugin is designed for Figma only, and not FigJam.
In the manifest, you'll see a reference to the ui.html file. Let's open it up.
Remember that HTML is responsible for the structure of our interface. This is where we indicate labels, buttons and fields that will be in our UI. Notice that there are already a few things written out for the sample plugin.
Finally, let's open up the code.ts file. You guessed it! This is where our TypeScript will go. This file is going to be responsible for adding logic and functionality to our plugin. You should see some pre-written TypeScript in here for our plugin to create rectangles.
Install typings
You might notice that there are a few errors in our code highlighted by Visual Studio.
To fix this, we need to install Figma's typings file into our project. Think of the typings file as an assistant while you use the Figma API. While the API documentation is there for you to reference as you build your plugin, the typings file contains annotations that can assist you while writing code by providing API suggestions and letting you know when you've missed an edge case.
Open up a new Terminal and run this script in the command line:
npm install --save-dev @figma/plugin-typings
If the installation was successful, you'll see something like this:
That should've fixed the errors in our TypeScript file. If we take a look at our Explorer again, you'll see a new directory called 'node_modules.' This is where the typings library is saved. In the index file are the annotations we mentioned earlier for the Figma Plugin API. Feel free to take a look if you're interested in how the types are defined, but make sure not to change anything here!
Setup compilation
With our dependencies set up, all that's left for us to do is to make sure that our TypeScript compiles to JavaScript in order for our plugin to run.
You might have noticed in the manifest.json file that the main field references a JavaScript file instead of the TypeScript file we looked at earlier.
Since Figma plugins run in the browser, and browsers only support JavaScript, the main field in our manifest will always point to a JavaScript file. Compilation is the process responsible for making sure that our TypeScript gets turned into usable JavaScript that allows our plugin to run.
Our plugin code will continuously change and evolve as we build it. Having to go through the compilation process every time that we save a new change to our file can become tedious. Instead, we should set up our project to watch for changes in code.ts then automatically compile into code.js by hitting CtrlShiftB in Windows, or CommandShiftB for Mac then selecting 'tsc:watch-tsconfig.json.'
Run the sample plugin
Now, we're ready to run the sample plugin! Go back to the design file we created in the Figma desktop app, navigate to Plugins and under Development, select the name of your sample plugin.
A modal will pop up with an input for the number of rectangles you want to create. For now, we can stick with the default of five rectangles and hit Create to run the plugin.
You should see that five orange rectangles have been created in the canvas.
Make some changes and run the new code
Great! Your environment is setup and ready for building plugins. Let's make a few test changes in code.ts and re-run our plugin.
In code.ts, on line 20 we'll find the code that creates a rectangle.
Let's modify this by replacing figma.createRectangle() with figma.createEllipse(). Save your changes, then go back to Figma and re-run the plugin. What do you notice? Has anything changed?
Now, on line 22 in code.ts you'll see something that says rect.fills with type and color values passed in. Let's change the rgb values to 0, 0 and 0. Don't forget to save your work! How are our shapes different?
As you can see, changing the code in our TypeScript file also changes the way that our plugin behaves. Using the Plugin API, we are able to interact with objects that exist on the canvas, or create new ones entirely!
Congratulations on getting your development environment set up and ready to go!
In the next video, we'll start building our own plugin and learn more about how to use Figma's Plugin API. I can't wait for us to get started! See you there!
Hi - I'm Sophie, from Figma's Product Education team. Welcome to the Build your first plugin course!
Plugins enhance your Figma experience. They're like the peanut butter to your jelly, the boba to your milk tea...or the pineapple to your pizza? They're programs built by the community that extend the functionality of Figma and FigJam.
Plugins are valuable pieces of software that let anyone contribute and customize Figma to fit every workflow. Figma's Community has hundreds of plugins that you can install with a single click.
Plugin examples
You can run installed plugins within a file without interrupting your flow.
Need a quick way to replace placeholder content with real data? Plugins like Content Reel by the team at Microsoft can help you get this done in a flash.
Plugins, like Mapsicle, let you access a third-party API so you can insert realistic maps into your file. Some plugins also have a relaunch button, so our teammates can relaunch the plugin later and make adjustments as we collaborate together.
Some plugins even let you play games in Figma like Kevin Kwok's multiplayer Pong Game.
About the course
Can’t find a plugin you're looking for? You can build it yourself for you or your team!
In this video series, we'll learn together and build a plugin that creates a customizable post for a social media app design. We'll also show you how to publish the plugin to the Figma Community.
Even if you’re not a programmer, you can still follow along and embark on your journey to becoming a plugin creator. We'll start with a basic introduction, then we'll walk through how to set up your environment, before taking you step-by step-through building your first plugin.
I am so excited to take you through this course. We'll have a lot of fun learning together, and soon you'll be on your way to becoming a plugin developer!
Ready to get started? Sign up for a free Figma account, and download the Figma desktop app which we'll use to develop our plugin. See you in the next video!
Hi again! Sophie here from Figma's Product Education team. Welcome back to the Build your first plugin course.
In the previous video, we saw a range of plugins that you can install from the Figma Community to customize and enhance your Figma experience.
Maybe you already have an idea for a plugin, and you're wondering "how exactly do we build a plugin?" In this series, we are going to take you through the process of building a plugin that creates components for social media posts in a Figma file.
Using APIs
To begin, we'll use Figma's plugin API to make sure our plugin can communicate with Figma. An API or Application Programming Interface allows two applications to talk to each other. Our plugin creates a request to Figma, and Figma's API delivers a response.
You can think of an API as a waiter at a restaurant. First, it takes an order from the customer, which in this case is our plugin. Then, the "waiter" takes that order to the kitchen and makes sure that the specifications have been met before serving the order to the table.
In order to use Figma's API, we first need to learn how to talk to it. This is done by referencing the Plugin API documentation on Figma's developer platform. Here, you'll find tons of information about how plugins work, as well as a reference to all the different components you can interact with using the API. If you're ever wondering, "can I do this with the API?" The docs are a great place to start!
Since the P in API stands for Programming, we need to use a programming language to use it. Well, actually a few different languages. But, don't worry! While it's handy to have some basic knowledge of writing code, it's not a requirement. We'll teach you everything you need to know, starting with a mini crash-course on some programming terminology. If you have previous experience writing code, you might want to skip ahead to the next video where we'll talk about environment setup.
Programming languages
Think of our plugin structure like a house. The programming languages we'll use all work together to specify the way our house looks and how it works.
TypeScript
First, we'll need to write some TypeScript, a programming language that is built on top of JavaScript. While you can also use JavaScript, Figma recommends writing your plugins with TypeScript. TypeScript helps us write code with fewer bugs, along with the added benefit of inline autocomplete with our preferred editor, Visual Studio Code. Our TypeScript code will make the plugin interactive and contain all of the logic of the plugin.
If TypeScript was an element of a house, it would be the ways in which you interact with the home. These are things like turning on a light, or opening a door.
HTML
Then we'll use HTML, which stands for HyperText Markup Language. You don't need to know what "hypertext" or "markup" means. Just know that it will define the structure of the plugins interface if you choose to create one. These are the labels, fields, and buttons that the user will see and interact with.
Typing this creates a text input field for our plugin UI that a user can type into:
<input type="text">
And adding this code above it gives that field a label, so our user knows that this field is for their name:
<label type="text">Name</label>
Each of these lines between the angled brackets are called tags. Here, we have a label tag, and an input tag.
Back to our house. Here, HTML would be the objects and surfaces that you can interact with. You can think of HTML as the structure of the house. For example, when you turn a light on, HTML is the light switch itself.
Or when you open a door? You guessed it. HTML is what gives us a door to open.
CSS
Finally, we'll give the plugin some style using CSS. CSS is how we define the look of the interface. We can style anything from the color or size of our label or text input, or the font we want the interface to use. We can even use CSS to change the position of those same elements in the UI.
CSS is usually the final touch to a project. Wouldn't a house be boring without some color? Maybe our door could be cornflower blue, or the roof could be firebrick red.
CSS allows us to customize the way that we present our UI to users.
The Figma global object
Technically, we could stop after writing only the TypeScript code and not use HTML and CSS to build an interface—not all plugins need a user interface. Let's jump into a quick example to show you what we mean.
Almost everything in JavaScript is an object. Much like objects that exist in the real world, JavaScript objects have their own functions and properties. What about something like a car? Can you think of functions and properties associated with this object?
A car could have the properties make, model and year, as well as the function drive.
let myCar = {
make,
model,
year,
drive(),
};
myCar.drive();
Figma has its own global object. Conveniently enough, this object is also named figma and has its own functions and properties that let us interact with the canvas.
Using the Plugin API, we can tell the figma object to do many different things.
For example, we can create a rectangle on the canvas by writing this statement:
figma.createRectangle();
Take a closer look at this line of code from our car example, and compare it to the one for creating a rectangle. What do you notice?
myCar.drive();
This is called dot notation. The 'dot' is how we call a function that belongs to an object.
You may also have noticed the parentheses after the function name. This is where we pass arguments into the function. Whether we pass arguments or not, depends on how the function was defined. We don't need to worry about that right now, so we'll leave them empty.
The semi-colon is how we end a statement in JavaScript. This is one way we can separate the different parts our code.
Most of the time, a basic program runs one statement at a time, in the order that they were written. Think of them as steps in a recipe. A plugin can have any number of statements, so it's a good idea to separate them.
Write your first statement
If you want to try writing your first statement and running it, you can open Figma's Developer Tools in the desktop app by going to the Plugins menu and hovering over Development. Click on Open console, and in the Console tab type in figma.createRectangle(); then hit Enter. You'll see that Figma has created a rectangle, just like if we had used the R shortcut and clicked on the canvas.
You can also make plugins for FigJam, and can use FigJam only API functions like this to create sticky notes:
figma.createSticky();
Preparing for environment setup
Nice! We could wrap this up, call it a day and publish this one-line plugin to the Community. We didn't even need to build a UI! However, we're going to build something a bit more complex than this and see some of the cool things we can do if our plugin did have an interface.
While we were able to test this one line of code in our developer tools, we'll actually need to set up a proper environment to build a plugin that uses all the tools we've just introduced.
There are a few ways to get our environment organized and ready for developing plugins. In this beginner series, we'll keep it simple by following Figma's Plugin setup guide and use the structure already built into the sample project.
I'm sure you're excited to start building your very first plugin. Now that we've gone through a brief overview of the process and tools we'll need, head over to the next video and get your environment set up! If you want to get a head start, make sure to download Visual Studio Code, since this is the development environment we'll be working in. See you in the next video!
Hi again! Sophie here from Figma's Product Education team and in the previous video, we set up our environment and installed the dependencies needed so we can start building our plugin.
By the end of this video we'll have a UI with some input elements and a button for our plugin. Before we do that, we should gather the requirements for our plugin in order to figure out what we need to create.
Copy the design file
You can get a copy of the design file with pre-made components by searching Figma for Beginners in the Community from the desktop app.
With the Community page open, create your own copy of the file.
If you do this from the web app, be sure to switch back to the desktop app since this is where we'll be doing our plugin development.
About the plugin
So, what are we building?
We're building a plugin with a user interface that contains a form that a user can fill out.
The plugin will take the user input, create a component instance for a post in our social media app, and populate the component with the information the user entered.
You might be wondering, why are we building this plugin? This example will teach us fundamental concepts like how to:
Take user input to create new components in a Figma file
This beginner series focuses on these important skills. You'll need a good foundation in order to build more complex plugins in the future! Once you have a solid grasp of some basic programming concepts and how the Figma Plugin API works, we'll be able to explore more advanced ways of using the API. This means we can eventually create features that will save us time during the design process!
The assets in the Figma for Beginners design file are similar to what you might find on other social media platforms like Twitter or Instagram. One thing these apps have in common are card components that serve different purposes. You could use the same skills learned in this video to build a plugin that creates cards like:
Travel website cards with an image, destination name, price and description
E-commerce shop items with an item name, price, and description
Or Podcast listings in a music app with a name and number of episodes
These are just a few examples of how you can apply what we're learning in this series. Once you build your first plugin, you might start to think about creating more complex plugins that use third-party APIs.
Third-party APIs are APIs outside of Figma that provide tons of information. There are APIs for almost anything you can think of. When we implement other APIs, we can build plugins that automatically pull data, instead of manually filling in this information. Think of something like a weather app plugin that generates cards with weather information. To do this we'd need to pull data from an external weather API. Weather data is constantly changing and varies day to day, so this saves us the trouble of manually entering all this information.
Plugin requirements
UI requirements
Now that you have a better idea of how we can apply the skills from this series, let's get back to building our plugin.
Let’s gather the project requirements before we set out to write any code. This gives us an overall idea of where the project is headed and a way to track our progress as we build each piece.
With the Figma for Beginners file open in the desktop app, go to the Components page and take a look at the Cards.
Here, you'll see a few variants of a Petma post component. Our plugin will be responsible for creating an instance of one of these post components. To do this, we'll need:
A window with a form for the user to fill out
A plugin name. We can do this by adding a heading to the form.
Input fields and labels for Username and Name
A text area and label for the Description of the post
Remember that an input field is generally a one-line field, so for multiple line entries we want to use text area. We could limit our Petma posts to a specific character count, or have no limit at all. Either way, we want to make sure we use an input type like text area that can handle large text entries.
You'll notice that there are several variants of the post component. We also want to provide our user with ways to:
Choose between light mode and dark mode
Specify whether they want no image, a single image or multiple images on their post
These features could be implemented a number of ways - with components like dropdowns, radio buttons or input fields.
Tom Lowry's lightweight UI library provides useful pre-built components we can add to our plugin. For example, the Switch component can be used to toggle between light mode and dark mode, and the Radio buttons would allow a user to select an option for the number of images in a post.
To save us time with creating these components, we are going to include Tom’s UI library in our project later.
Finally, we'll add a button to submit all of the information from the form.
Functional requirements
Now that we know the requirements for our user interface, let's think about some of the functional requirements of our plugin.
Using the Figma API, we’ll learn how to:
Open a modal in order to display our user interface.
Send form information to our plugin logic once the user clicks Submit.
Find the appropriate component set and its variants from our Figma for Beginners file.
Check which variant of the card component the user has selected based on the form.
Load the same fonts used in the existing card components.
Use a method from the Figma API to create a new Post component.
Overwrite text and use other tools like the Math.random function to change the content in a Post component.
Add the new Post component to the Figma file.
Tell Figma to zoom in to the newly created Post.
Now that we’ve gathered our requirements... we are finally ready to write some code!
Building the UI
Let's open up the project that we started in the last video. The first thing we need to do is delete all code from code.ts and ui.html. We won't be using the sample plugin code since we're building ours from scratch.
Make sure that you add editorType:figma to the manifest.json file in order for the plugin to work in the Figma desktop app.
Taking a look at our checklist, we want a modal to pop up when we run our plugin.
In ui.html, let's give our plugin a title. We can use an <h1> heading tag for this. This is the message that will display in the modal once it pops up.
The Figma API has a showUI function that displays a plugin’s interface. This function creates a modal that contains the html markup we pass into it. For example, figma.showUI(”<h1>Hello, world!</h1>”) would result in something like this:
Now, replace that line of code with figma.showUI(__html__). By passing in __html__ , the modal is able to display the contents of your HTML file.
In your manifest.json file, you’ll see that the 'ui' property is set to 'ui.html.' This is how we specify which file the __html__ variable is referring to.
First run of the plugin
So far, we’ve added a heading to our html file, added the showUI function to code.ts and confirmed that our manifest is pointing to the right file. This gives us enough code to run our plugin for the first time.
Remember, we can use the command CommandShiftB then select the ‘watch’ script.
Since the file is now watching for changes, we don’t need to worry about updating the build manually while the project is open in Visual Studio.
Going back to the Figma for Beginners file in the desktop app, we can select our plugin to run it. If the build was successful, you should see a modal pop up with the message we wrote in our html file.
Awesome! Now that you see how changes in our code affect the plugin in the Desktop app, we can continue constructing our UI.
Create a form
Right now, all our plugin does is display a heading inside of a modal, which isn’t very useful.
We need to add a form that will allow the user to interact with our plugin.
We want the input fields on this form to match the fields on the component we’re making. This includes inputs for Username, Name and the Description of the Post. Finally, we’ll provide a way for them to choose between light mode or dark mode, and to select the number of images in a Post.
Back in ui.html, let’s add a <div> tag to create a section for our text inputs.
<div> tags are a great way to divide up content in a page. We can use it to group other HTML tags in a way that is easier to visualize. In this div section, we’re going to use the <input> tag to create inputs for the username, name and description. Don’t forget to add a corresponding label to each input!
While the input types for username and name are “text”, remember that description will be a “textarea”, because it needs to hold a larger amount of characters. Since we’re still in watch mode in Visual Studio, we should be able to save our file and view the form when we run the plugin again!
We can add some basic styling to make sure that our inputs are being displayed as block elements and not wrapping. To do this, add this block of code to the top of your html file:
<style>
input {
display: block;
}
</style>
So far, we’ve got our form with a heading, as well as input fields for username and name, and a textarea for description.
Next, we need to decide how we’re going to represent the choice between dark mode and the default styling, which we’ll refer to as light mode. While there are several ways for us to approach this, something that immediately comes to mind is a switch that toggles between the two options.
Creating a custom element like this would require more CSS on our part and additional programming logic that we don’t want to worry about at this point. To make things easier, we are going to use Thomas Lowry’s Figma Plugin UI Library. By including this in our project, we can access ready to use elements without having to build them from scratch.
To include the UI Library in our plugin project, add the following line of code to the top of ui.html:
Taking a look at the UI library’s ReadMe on GitHub, you’ll see that we need to include specific classes to style our elements.
Let’s add some classes to our inputs and see what happens.
Great! Our input fields should look a bit different than they did before. This is thanks to the CSS already included in the UI Library. With these built-in styles, we can even do things like specify the number of rows that a text area takes up.
Now, we can add the switch that allows our user to turn Dark mode on and off. We can find the code for a Switch in the README (feel free to copy the block of code below).
We highly recommend typing out this code yourself while learning how to build plugins, but if you need to reference this code in the future, check out this link to the GitHub repository.
With the Dark mode switch added, we need to give the user an option between no image, a single image, or a carousel in their post.
Since they will only have to choose one of these options for every post created, radio buttons are a great way to represent this.
We’ll create a div with a class of “radio” to make sure the radio buttons are part of the same group, then we’ll add inputs and labels for each option.
Note that while each radio button has a different id, they all have the class "radio__button" and the name "variantGroup". Make sure that the labels correspond to the correct input by using the input id.
Before running the plugin again, let’s add a Submit button at the end of the form and give it the id attribute ‘submit post’.
We’ve just completed our last two UI requirements!
Let’s run the plugin!
Default text values
Awesome! Our form is built out and ready to start taking user input.
Before moving on to the next section, we can add some default values for our text inputs using the value attribute. Now is also a great time for us to make sure that all of our inputs have an id attribute.
Next, we can resize the plugin modal by going to code.ts and adding the Figma resize method. This method takes in numbers to represent the width and height of the modal - let’s try 500 by 500:
figma.ui.resize(500,500)
Finally, let’s give our form a bit more style.
<style>
body {
padding: 2em;
}
div {
margin: 1em;
}
input {
display: block;
}
</style>
One of our functional requirements is to take form input and send that information to our plugin when the user clicks Submit. How exactly do we do this?
Event listeners
In JavaScript, there is something called an event listener that waits for a specific event like a mouse click or key press. The event listener then handles what happens once the event occurs. You’ve likely encountered event listeners on the web. For example, when you press the up or down keys, you can scroll through a web page. Or when you click a button to play a video or sound file - these actions are handled by event listeners.
First, we’ll need to write some code that makes something happen when the user clicks the Submit button. We need to indicate that this event is happening in the document where our button exists. Then, we need to select the correct element by targeting its id. This is the element that we’re attaching the event listener to. In this case, that’s our Submit button with the id ‘submit-post.’ Finally, we’ll use the ‘onlick’ method to specify that something should happen once a user clicks on the Submit button. To finish writing this method, we need to add a parentheses and some curly brackets. The curly brackets will contain the logic that runs once the click event happens.
Let’s go ahead and add this code to our plugin. We can do this by using <script> tags at the bottom of ui.html and putting our Javascript code in between them. <script> tags allow us to embed JavaScript directly into our HTML file and are typically used to work with dynamic content on a page.
We still haven’t decided what happens when someone clicks the Submit button. For now, let’s add the line:
console.log("Building my first plugin!")
Save your file and make sure that Visual Studio is watching for changes. If you’re no longer in ‘watch’ mode, just hit COMMANDShiftB again. Run the plugin, then open the console by hovering over Development in the Plugin menu, and selecting Open console. In the plugin form, click Submit. If we take a look at our console, we should see the message “Building my first plugin!”
Great job! Our event listener noticed the click on the submit button, then handled it by printing out a message to the console.
Now, how do we send the form information to the rest of the plugin code that will live in our Typescript file? First, we need to pull the values from each form input when the click event happens.
Let’s start by creating a constant called name within our event listener. A constant in JavaScript is a type of variable with a value that can’t be changed once it is assigned. In this constant, we’ll store the current value of the name input by assigning document.getElementById('name').value
Why don’t you try doing the same thing with the username and description?
We can check these values by logging each variable to the console. Save your changes and run the plugin. Remember to open your console! Type in some random text for name, username and description then click Submit. Are you able to see the logs for the values you entered?
If not, try double-checking that your syntax is correct by comparing it to what we have below:
For the dark mode switch, since it is a checkbox input type, we need to determine whether or not it is in a checked state. Similar to our text inputs, we’re going to create a constant to store this information. Rather than storing the value of the dark mode element, we’ll use the ‘checked’ method that returns either ‘true’ or ‘false’ depending on whether or not the switch is toggled.
If the variable stores ‘true’ then we know that dark mode is selected and vice versa.
Now, let’s add some value attributes to each one of our radio inputs. We’ll use string values 1, 2, and 3. For radio buttons, we need to use a querySelector to target the group of buttons by their shared name, rather than selecting a single element by its id. Then, we’ll find the checked radio button and grab its value. This will either be 1, 2, or 3 depending on the option that the user submits.
We won’t be diving into query selectors in this series, so if you’d like to learn more, check out this additional resource.
Write a couple of console logs for the two new variables you’ve created, then run the plugin.
Like our last test, type in some text for name, username and description. Toggle the switch to turn Dark mode on, and select Carousel from the list of options. Submit the form and check the console. After the text inputs for name, username and description, you should see a log that prints ‘true’ and another that prints out ‘3’.
Awesome! We are successfully pulling all the values from our form inputs.
Post message method
We’ve captured the values from our form fields and logged them in the console. How do we put these values to use in the rest of our plugin? We are going to use the parent post message method. This will send over data from the form to our Typescript file. Go ahead and add this line of code to your Javascript in ui.html within the event listener you created.
parent.postMessage(message,'*')
This will go at the very end of the code in our event listener, right before the closing curly brace.
We’ll replace the message parameter with an object that contains our form variables. Remember that a function parameter acts as a placeholder with a default value of undefined until we pass in an argument. In this case, that is the 'pluginMessage' object with the values - name, username, description, darkModeState and imageVariant - which are pulled from the form once it’s submitted.
In code.ts, we can use the Figma API’s on message method:
figma.ui.onmessage = pluginMessage => {}
This receives the same object that we send over from the postMessage in our event listener. Since pluginMessage is an object, we need to use dot notation to access its different properties. For example, to access the name property, we would write pluginMessage.name or to check for the dark mode state we would write pluginMessage.darkModeState.
Let’s validate that the pluginMessage from ui.html is successfully received by our Typescript file.
In our on message method, console log all of the variables from the pluginMessage object. Once you’ve done this, go ahead and delete the console logs from your event listener.
Save your changes and re-run the plugin. When you check your console, you should see logs for all of your form variables. These console logs are now coming from your Typescript file! You’ve successfully sent information from the plugin form back into your program logic. Amazing job!
An important thing to keep in mind as you build plugins: we should always close our plugin once it’s done running. To do this, we’ll add the line figma.closePlugin() at the end of our on message method.
This method ensures that the plugin UI is closed once we are done using it and that access to the currentPage is disabled. This way, we can avoid getting any unexpected behavior from our plugin.
Conditional logic
Now that we are returning information from the form, we can use these variables in our plugin logic. For example, if the user selects Dark mode, let’s print out a message that says “Welcome to the dark side.” Otherwise, we’ll print out a message saying “I’m Mr.LightSide”
if(pluginMessage.darkModeState === true) {
console.log("Welcome to the dark side.");
} else {
console.log("I'm Mr.LightSide");
}
This block of code is called a conditional. A conditional is a statement that tells our program what action to take depending on whether a condition is true or false. In this case, we are telling our program that IF the darkModeState from the form is set to ‘true’, print out “Welcome to the dark side.” Otherwise, print out the other message.
The else statement in a conditional acts as a default path in case the ‘if’ condition isn’t met. This concept is something that we’ll return to as we develop our plugin.
Working with components
Now that we are successfully using form information in our plugin logic, how do we use information from components that already exist on the canvas?
Once again, we’ll need to reference the Figma Plugin API documentation. In the Figma API, there are different node types that represent layers on the canvas. Each of these nodes correspond to different Figma objects and layers, and have their own set of properties. For example, we have the RectangleNode which is a basic shape node that represents a Rectangle on the canvas. Some of its properties include width, height, and corner radius.
There’s also a TextNode that allows us to reference text components in Figma. In this node we’ll find properties like .characters that allow us to read or write the characters within a text component. There are also methods for finding text properties like fontSize, fontName, letterSpacing and more.
Let’s continue exploring nodes. Go back to the Figma for Beginners file and open up the Components page. This group of Post components can be referred to as a component set.
You guessed it, there is a matching COMPONENT_SET node type that we can use to reference component sets on the canvas.
To get information from this particular component set, there is a findOne method that will return a single matching node from the canvas. For example, we can write:
figma.root tells the method where to look for the node. Root here refers to the entire Figma document. We want to use this method as opposed to figma.currentPage because we want to be able to find this node no matter what page we’re currently on in the document.
Here we are telling the findOne method to locate a node whose node type is component set and has the name “post”. Let’s take this line of code and test it out in the console to see what it returns.
You should see a similar ComponentSetNode returned with an id. Click on the arrow to the left to expand the object. What do you notice? These are all the properties of our selected ComponentSet. Let’s take a look at the name property to make sure that we have the right node.
There it is! This component set is named “post” so we know that our findOne method found the correct node successfully.
Go ahead and explore some of the other properties. What do you see when you expand the children property? It looks like this component set has six child components. Where do you think those are coming from? Exactly! Those six components are the six variants of our Post component.
Let’s move this line of code over to our Typescript file and store the component set in a variable named ‘postComponentSet’.
We’ll add ‘as ComponentSetNode’ to the end of this line to make sure that when our TypeScript is compiled, the variable will still be seen as a Component Set, just in case JavaScript interprets it as a different node type.
Test the new variable by logging ‘postComponentSet’. While we’re here, we may as well log some of the component set’s properties like ‘postComponentSet.children’ and ‘postComponentSet.name’. We’ll re-run the plugin and open up the console. You should see that we’re getting the same object as we were earlier! We can verify this with the type Component Set and the object name, which is “post.”
When we test this in our console, we get a Component node. Take a look at the defaultVariant’s name property. What do you notice? This name exactly matches the name of the component on the canvas.
Let’s find this component, and you’ll see that this is in fact the default variant in the top-left position of the component set.
Before we go back to the rest of our code, let’s run one more test in the developer console. Let’s try creating an instance of the default variant. The Component node type has a createInstance method that does exactly this. Add .createInstance() to your previous line of code.
We get an InstanceNode object. What just happened? If you don’t see anything, try zooming out. Notice anything different? You should see the default variant that we just created an instance of! Nice!
Now, we can work on moving this into our Typescript file. First, we’ll store the default variant as a separate variable from our component set. Since we’ve already got our component set in a variable, we can simplify this by saying postComponentSet.defaultVariant
Don’t forget to add “as ComponentNode” at the end of this line to remind our compiler to read this as a component node.
Finally, create an instance of this default variable using the createInstance() method and run the plugin again.
Now, when we submit the form, no matter what the input is, the plugin creates an instance of the defaultVariant.
Although we are successfully able to find and create an instance of the defaultVariant, we can’t forget about the others! The great news is we can use the same findOne method to select the other variants from the component set!
Create a new variable called ‘defaultDark’ and using findOne, we’ll store the variant with the name “Image none, Dark mode true”, which should be this component here.
Note that the name we put in our findOne method needs to exactly match the name of the component on the canvas.
const defaultDark = postComponentSet.findOne(node => node.type == "COMPONENT" && node.name == "Image=none, Dark mode=true") as ComponentNode;
Remember the conditional we wrote earlier that checks whether or not the user selected dark mode? Let’s put it to use! Delete the console logs within the if-else blocks and instead, if dark mode is selected, create an instance of the dark mode component by writing defaultDark.createInstance(). Otherwise, if dark mode isn’t selected, write defaultVariant.createInstance().
const defaultDark = postComponentSet.findOne(node => node.type == "COMPONENT" && node.name == "Image=none, Dark mode=true") as ComponentNode;
if (pluginMessage.imageVariant === true) {
defaultDark.createInstance()
} else {
defaultVariant.createInstance()
}
We’ll run the plugin a couple of times to see if our conditional logic is working. Let’s add some text to our inputs, and for this round we won’t select Dark mode. Right now, we can choose any of the image options since we haven’t written code to handle that yet. Once you submit the form, it should still create the defaultVariant from earlier. Then, we’ll fill out the form again, this time with Dark mode selected and hit submit. If we wrote our conditional correctly, the plugin should have created a dark mode variant with no image. Awesome job!
Switch case
Using conditional logic, we told our plugin to create a different component based on user input. How do we implement this same concept to create the rest of the variants in our component set?
In our html, we can see that the way we specify which variant the plugin creates is with the imageVariant variable. This variable checks the value of the radio button that is selected. A returned value of 1 means no image, 2 means a single image, and 3 means the carousel variant. We can check these values in our typescript by logging pluginMessage.imageVariant. Let’s run our plugin a few times and test these different values. You’ll see that the value we get back directly corresponds with the radio button we selected when we submitted our form.
Back to our implementation. We have an additional layer of decision making to consider.
First, we ask the question do we want dark mode? Yes or no? If yes, then which dark mode variant do we want - 1, 2 or 3? If no, then which light mode variant do we want - 1, 2, or 3?
There are a couple of ways we can represent this in our plugin logic. One way is by creating nested if-else statements. For example, if dark mode is true, we can nest if else statements that will then check for the imageVariant.
However, as you can see this looks a bit cluttered and we want to make sure our code is as concise and easy to read as possible. A better option would be to use a different conditional logic structure called a switchcase.
A switch case evaluates one expression and decides which case to execute depending on the resulting value. For example, pluginMessage.imageVariant will either evaluate to a value of 1, 2 or 3, so we can write our switch case like this:
if(pluginMessage.darkModeState === true){
switch (pluginMessage.imageVariant) {
case "2":
// create instance of dark mode, single image
break;
case "3":
// create instance of dark mode, carousel
break;
default:
// create instance of dark mode, no image
break;
}
}
You’ll notice that instead of creating a case “1” for the dark mode variant with no image, we’ve gone ahead and added this variant to the default case. The default case in a switch statement will run if none of the other cases match the evaluated expression. So if the value of imageVariant is not 2 or 3, then run the default case. This is useful in case our plugin somehow receives a value that we aren’t expecting.
It’s also important to note that each case ends with the ‘break’ keyword and a semicolon. When a switch statement finds a matching case, all of the code inside the case will execute up until the break. The break statement is what tells our program to stop.
This is a great time to pause the video and try writing a switch statement on your own! Finish out the conditional logic by creating a switch statement within the else code block to find the light mode variants. For now, don’t worry about creating instances of the variants. You can use comments as placeholders just like we’ve done here. Hit play once you’re ready to continue!
Welcome back! Hopefully you had a chance to write your own switch statement. At this point, you should have some code that looks like this:
if(pluginMessage.darkModeState === true){
switch (pluginMessage.imageVariant) {
case 2:
// create instance of dark mode, single image
break;
case 3:
// create instance of dark mode, carousel
break;
default:
// create instance of dark mode, no image
break;
}
} else {
switch (pluginMessage.imageVariant) {
case 2:
// create instance of light mode, single image
break;
case 3:
// create instance of light mode, carousel
break;
default:
// create instance of light mode, no image
break;
}
}
Creating variant instances
We’re getting there! Our plugin is really starting to take shape. Our next task is figuring out how to create instances of all these different variants. As of now we are only able to create instances of the default variant and one of the dark mode variants.
One way we can approach this is by creating different variables for all the other variants, like what we’ve done with defaultVariant and defaultDark. Instead, what if we could just have one variable that gets assigned a component depending on which case is met in our switch statement?
To do this, we’ll create a variable outside of our conditional logic called ‘selectedVariant.’
Notice that instead of a constant variable, we are creating a let variable here. Unlike a constant that can’t be changed, a let variable allows us to reassign the value depending on which variant we create an instance of. For example, if the user doesn’t select dark mode and selects the no image option, we would want to create an instance of the default variant. In the case, we’ll assign ‘selectedVariant’ the defaultVariant from the postComponentSet.
We can apply the same concept to assign the rest of the variants within our switch statements. Since the other variants are not the default, we can utilize the findOne method similar to the way we used it to find the first dark mode variant. To demonstrate, under the default case for the dark mode path of the conditional, your code might look like this:
Again, it’s important to note that the node name matches the name of the component on the canvas exactly.
This is the property that will allow us to differentiate between the variants. You can pause here and complete the rest of the switch case statements. Replace your comments by assigning the correct findOne method to the selectedVariant variable. Press play once you’re ready for the next part.
Once you’re done updating the switch cases, your conditional logic should look like this:
We can go ahead and delete our defaultVariant and defaultDark variables since we don’t need them anymore. Remember to save your work!
Before we run our plugin to test this, we can’t forget to create an instance of the selectedVariant!
selectedVariant.createInstance();
We’ll do this right after the conditional and before the closePlugin method. Great! Let’s open up our file and test out our changes. Run the plugin a few times and try different combinations of dark mode with the number of images to see if you can get all the Post component variants.
If you’re not able to create the six variants, make sure to check your syntax. Are the names of the nodes matching? Are your switch statements checking for string values rather than numbers? Attention to detail is really important here!
Update the default text
Spectacular job! If your plugin is working properly, you should be able to create all six Post component variants. However, with the way our plugin is at the moment, no matter what we type in for username, name and description, we are still creating new instances with the component’s original text. We can change this by selecting the TextNodes from the newly created component and overwriting them with the information submitted in the form.
Remember that when we create an instance using the createInstance method, what we are actually doing is creating a copy of the selected object.
First, we need a way to reference the new Post component. We can do this by storing the new instance in a variable like this:
const newPost = postTemplate.createInstance();
Then, we’ll create variables for name, username and description to store the corresponding TextNodes.
Notice that we are looking for these nodes from within the newPost, which stores the new instance that we are going to create. We can find each node by name and by checking that they are of the TextNode type. Before we overwrite the current TextNodes, let’s check that we are in fact returning the right text nodes. We can use the TextNode characters property to see the text being stored in each node.
Write a few logs to view the characters in the text variables we just created.
Remember that those values are sent to our Typescript file from the pluginMessage object and we can access them using dot notation.
Loading fonts
With the characters reassigned, ideally we should be overwriting the text nodes. However, when we run the plugin, you’ll likely encounter a Plugin Error that looks like this:
This is telling us that we can’t overwrite the TextNode due to an unloaded font. Don’t worry! We can fix it. It’s important to know that anytime we are changing the contents of a TextNode, we first need to load the font that the text node is using.
It looks like the font used in our Post component is Rubik, Regular. We’ll load this font in at the top of our onMessage method by using the Figma loadFontAsync function.
Notice the ‘await’ keyword at the beginning of this line. That’s because this function is asynchronous and returns something called a ‘Promise’. Since the loadFont function only works to load fonts already accessible in the Figma editor, the ‘Promise’ will either resolve, meaning the font was found and loaded successfully, or reject and give us an error.
We won’t be diving into asynchronous methods or Promises in this course, so check out the link in the description below if you want to learn more!
Once we’ve done that, we’ll have to do a small refactor of our code and test it again.
figma.ui.onmessage = async(pluginMessage) => {
All we’ve done is add the async keyword and put the pluginMessage parameter in parentheses.
Once you’re done adding these changes, run the plugin again. If it’s successful, you should see the text in the new component being overwritten with your form inputs. Wonderful! Take a moment to give yourself a huuuuuge pat on the back because you’ve just built your very first Figma plugin!
Next steps
You can continue working on this plugin and even implement additional features! For example, we can add some random number generators to randomize the number of likes and comments when we generate a new Post. We can overwrite these text nodes by first locating the node with the findOne method, then assigning the random number function to change the TextNode’s characters.
In this example, every time we run the plugin, our code will generate a random number from 1 - 1000 and assign it to the number of likes and comments in a Post component.
We could also make it easier to view our new Post by writing in some code that tells the editor to focus on the new component once it’s created. There’s a scrollAndZoomIntoView method which automatically adjusts the viewport to focus on the selected nodes.
figma.viewport.scrollAndZoomIntoView();
To have this method focus on our new Post component node, we need to add this line right after we load our font:
const nodes: SceneNode[] = [];
We just created a variable called ‘nodes’ that is currently an empty array. An array is typically used to store multiple elements. However, in this case we are just adding the new Post to the array since the scroll and zoom into view method is expecting an array to be passed in.
Although we won’t be diving into Arrays in this course, remember to check out the description below to learn more!
Animation here would be really helpful to explain the concept of an array and that we need to add our Post to it since the method is expecting an array type passed in.
We can add our new Post to the list of nodes using the push method:
nodes.push(newPost)
This line should be added at the bottom of our code, right before the close plugin method. Remember that newPost is the name we’ve given the variable that stores the new instance of our selectedVariant.
let newPost = selectedVariant.createInstance();
After the newPost is added into the nodes variable, we can tell the scrollAndZoom method to focus on that component by passing in ‘nodes’.
figma.viewport.scrollAndZoomIntoView(nodes);
Run the plugin again, and you’ll notice that it’s so much easier to find our new Post component now!
These are just a few ideas you can implement, so have fun and get creative!
Once again, congratulations on building your very first Figma plugin!
I hope that learning these fundamentals helped you on your journey to becoming a plugin developer! Keep on learning and we can’t wait to see all of the cool things you come up with. In the next video, we’ll show you how to publish your plugins to the community so you can share what you’ve created. See you there!
Welcome to part five of the Build Your First Plugin series! In this video, we’re going to show you how to publish your own plugins to the Figma Community. The Figma Community is home to thousands of templates, widgets, and plugins built by other Figma users. We’ll learn how to add our work to the Community so that others can find and install our plugin!
If you’ve been following along on our video series, you should already have a plugin ready to publish! If not, check out videos one through four to learn how you can build your very first Figma plugin.
To publish a plugin to the Community, we’ll need to use the Figma desktop app. Let’s open up the desktop app, and navigate to the left sidebar. Click on Explore community. This will open up the Figma Community page in the desktop app.
In the top-right of the Community page, click on the blue Publish button and a modal will pop up displaying your Figma files. In the top-left of this modal, navigate to Plugins to view a list of plugin projects that are available for publishing.
We’ll select the plugin we built in the previous video, hit Next and the Publish plugin modal will pop up.
Every plugin has its own page in the Figma Community. This allows other members of the Community to find and install a plugin, and learn more about what each plugin does. In the Publish plugin modal, we can provide the information we want to display on our plugin page. We recommend having this information ready before starting the publishing process.
Let’s add an icon to represent our plugin in the Community and in the Editor when a user runs our plugin. Although I already have an icon ready to use here, this is something you can create yourself! Just make sure to follow the recommended dimensions outlined in the Publish plugin modal. Luckily, Figma makes this easy by having frame presets available for plugin publishing. To use the plugin frame presets, open a design file, select the Frame tool, then click on the Prototype tab in the right sidebar. Under the Figma Community dropdown, you should see presets available for creating a plugin icon, a profile banner and a plugin cover. Nice!
Next, we’ll give our plugin a name. This can be as descriptive or creative as you want! Users will be able to search for your plugin using this name.
Then, we’ll write a description of our plugin. This is where we can explain what our plugin does and how to use it.
We can also add some cover art to display at the top of our plugin page. Again, make sure to follow the recommended dimensions outlined in the modal so that your image looks its best!
Let’s not forget to add relevant tags to the plugin. We can have up to twelve keywords and these can be anything that would make it easier for other Community members to find our plugin.
It’s important to note that as a plugin creator, it’s your responsibility to provide support for your plugins. Under support contact, we should provide an email address, website or help center link, just in case users have any questions about the plugin.
You’ll see that the publish plugin modal has automatically assigned you as the plugin Creator. If anyone else assisted in the building of this plugin, you can credit them here by entering their Figma Community handle.
Under Plugin info, you may get an error that says “Invalid ID in manifest.json.”
To fix this issue, click on the “Generate ID” button to the right. You should now see a message that says “Please add this to your manifest.json file” with an id property and value underneath it.
First, we’ll copy this newly generated id, then open up the plugin project in Visual Studio Code. In the manifest.json file, replace the current id property and value with the new id you generated in the modal.
Save this change, then hit Command Shift B to watch for changes. If we made the change correctly, our project should compile successfully with no errors. Great!
Let’s head back to the publish plugin modal in our desktop app. By default, comments are allowed on the plugin page since they are a way for other Community members to provide feedback and make feature requests. However, if you’d like to turn this off, you can uncheck the box in the Comments section here.
Finally, let’s scroll back up to the top of this modal to see a preview of our plugin. This is a great time to check for typos and verify the information we filled in.
If you like what you see, go ahead and hit Publish at the bottom of the modal.
Congratulations! You’ve submitted your first Figma plugin for review! Figma will contact you through your Figma account email to let you know if your plugin has been approved.
Learn more about publishing plugins and the review process ->
Thank you so much for following along in the Build Your First Plugin series. We hope that you had fun learning with us and we can’t wait to see your plugins in the Figma Community. Have an idea for another video series you’d like to see? Let us know in the comments below! See you next time!