Figma Plugin API: How to Load and Use Fonts
Tags: typescript, html, figma, plugin
Published: 2022-02-06 07:45:12

Working with Figma text through the Figma Plugin API is a lot trickier than you might think. All the text inside Figma files are _nodes_ called **TextNodes**. Essentially, nodes are **layers** in Figma. With text nodes you have to think about _mixed styles_, _missing fonts_ and _loading fonts_.

For now, we concentrate on loading fonts.

If you wish to change the content of a TextNode, **you must load its font**.

---

## TL;DR

Here's one way of loading a font and manipulating text:

```typescript
// Load font via async function
const myFontLoadingFunction = async () => {
  await figma.loadFontAsync({ family: "Work Sans", style: "Bold" })
}

// Another function where we use the loaded font
const myAnotherFunction = () => {
  // Create text layer
  const myTextLayer = figma.createText()
  // Set the font
  myTextLayer.fontName = { family: "Work Sans", style: "Bold" }
  // Set text to uppercase
  myTextLayer.textCase = "UPPER"
  // Set text content
  myTextLayer.characters = "This is my title"
  // Add text layer to current page in Figma
  figma.currentPage.appendChild(myTextLayer);
}

// Use font only after the Promise is resolved
myFontLoadingFunction().then(() => {
  myAnotherFunction()
})
```

That's basically it. If you want to know more about this subject, just keep on reading.

---

### Glossary

1. [About loading fonts](#about-loading-fonts)
1. [How to load fonts](#how-to-load-fonts)
1. [What can you do with fonts and text](#what-can-you-do-with-fonts-and-text)

You can find the official _Figma Plugin documentation_ [page about **TextNodes** here](https://www.figma.com/plugin-docs/api/TextNode/) but I believe the docs could be better and that's why I wrote this blog post.

---

## About loading fonts

The docs tells us this important thing about text and fonts:

> The important thing with text is that **changing the content of a text node requires its font to be loaded and that fonts are not always available.** If you attempt to change, say, `fontName` without first loading the font for that text node, the plugin will throw an exception.

I found out that the exception will look like this in your console.

![Image of an error in console.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/68j548abd5v9xp9cyvqb.jpg)

**So, basically every time you make changes to text content or its properties, you have to load its font.** Only when you're changing properties like fill colour or stroke, you **do not** need to load the fonts.

---

## How to load fonts

**TextNodes** have a property called `fontName` which is a javascript object that contains the font family and font style. The default font is `{ family: "Roboto", style: "Regular" }`. In our example we want to use **Work Sans, Bold**.

(As a sidenote: You can load any font thats already accessible in the Figma editor. You cannot load fonts from the internet.)

The documentation says that _"Loading a font is done via `figma.loadFontAsync(fontname)`"_ and maybe for someone that is enough but, as a designer, I was a bit confused when I tried it and it didn't work.

```typescript
// Like in the docs => figma.loadFontAsync(fontname)
figma.loadFontAsync({ family: "Work Sans", style: "Bold" })
```

On it's own, this code isn't enough. This is when the **error** appears in the console. As we dive deeper into the docs we find this about the **loadFontAsync** property:

> (loadFontAsync) Makes a font available in the plugin for use when creating and modifying text. Calling this function is necessary to modify any property of a text node that may cause the rendered text to change, including .characters, .fontSize, .fontName, etc.

And from it's signature (found in the docs) `loadFontAsync(fontName: FontName): Promise<void>` we can see that it returns a **Promise**. So, we must enchance our code by creating an "async/await" function:

```typescript
const myFontLoadingFunction = async () => {
  await figma.loadFontAsync({ family: "Work Sans", style: "Bold" })
}
```

After the **loadFontAsync** Promise is resolved, we can use the `then()` method that returns a new Promise and when that is a success we can do what we initially wanted.

```typescript
myFontLoadingFunction().then(() => {
  // Success!

  // Add your code here to do something with the loaded font!
})
```

You can read more about [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) and the [`then()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then) from the MDN docs.

All the code once more:

```typescript
// Load font via async function
const myFontLoadingFunction = async () => {
  await figma.loadFontAsync({ family: "Work Sans", style: "Bold" })
}

// Another function where we use the loaded font
const myAnotherFunction = () => {
  // Create text layer
  const myTextLayer = figma.createText()
  // Set the font
  myTextLayer.fontName = { family: "Work Sans", style: "Bold" }
  // Set text to uppercase
  myTextLayer.textCase = "UPPER"
  // Set text content
  myTextLayer.characters = "This is my title"
  // Add text layer to current page in Figma
  figma.currentPage.appendChild(myTextLayer);
}

// Use font only after the Promise is resolved
myFontLoadingFunction().then(() => {
  myAnotherFunction()
})
```

---

## What can you do with fonts and text

After you have your fonts loaded you can use the following properties and functions of a TextNode:

* **characters** = set/write your text content
* **fontSize** = set font size
* **fontName** = set font family and style/weight
* **textStyleId** = set TextStyle using TextStyle id
* **textCase** = set text casing to uppercase etc.
* **textDecoration** = set decoration to underline/strikethrough
* **letterSpacing** = set letter spacing in pixels or percents
* **lineHeight** = set line height in pixels or percents
* **setRangeFontSize()** = set font size to characters in range
* **setRangeFontName()** = set font to characters in range
* **setRangeTextCase()** = set text casing to characters in range
* **setRangeTextDecoration()** = set text decoration to characters in range
* **setRangeLetterSpacing()** = set letter spacing to characters in range
* **setRangeLineHeight()** = set line height to characters in range
* **setRangeTextStyleId()** = set TextStyle to characters in range

You can check out all the **TextNode** properties and functions [here](https://www.figma.com/plugin-docs/api/TextNode/).

---

Have fun developing Figma plugins 🔥 I hope you found this article helpful!

[Follow me on Twitter](https://twitter.com/laurilllll) for more **Figma**, **CSS** and **Design System** content 💪