Tuesday, April 23, 2024
HomeWeb developmentConstructing Interactive Figma Widgets | CSS-Methods

Constructing Interactive Figma Widgets | CSS-Methods


Figma has all the time inspired collaboration between builders and designers. It strives on an limitless treasury of community-made plugins. Want 3D parts? There’s a plugin for that. Want summary SVGs? There’s a plugin for that, too.

That stated, the design a part of Figma has all the time been comparatively static — all the time working with unmovable rectangles linked to one another by way of predefined consumer interactions. However what if I advised you that your designs may immediately come to life — that they may very well be animated, interactive, and even stateful? Then, what would separate idea from implementation?

Figma introduced in June that it’s bringing JavaScript-powered widgets to the desk. Now, designers have can browse and implement logic-driven parts straight in Figma!

Say whats up to the Widgets API! You need to know what it’s and the right way to use it? That’s precisely what we’re going to do collectively on this submit.

Figma widgets open up tons of potentialities

Think about that you just’re working across the clock together with your companion to design a big restaurant utility. You’re each already collaborating on the identical Figma board; each of you might be sharing the very same doc with modifications occurring on the fly.

Certainly, you already know that collaboration includes extra that simply the design course of:

  • challenge administration,
  • internet hosting polls to assemble votes,
  • importing and visualizing mock information,
  • and even perhaps enjoying a multiplayer sport to cool-off after many hours of labor.

We simply require one individual to handle every part and send-out hyperlinks to different members of the group. However oh, that’s not very environment friendly, is it?

Effectively, that’s the place widgets come into play. We are able to conceivably do all of that — sure, every part —with out ever leaving Figma.

Listed here are only a few of the methods you would possibly need to use widgets in Figma:

The listing goes on and on. As you may inform, there’s already a plethora of widgets that you may freely use in your paperwork. In truth, you may add Widgets straight to your board from the Widgets menu (Shift+I).

However we’re not right here to learn to use widgets, as a result of that’s straightforward. Allow us to do what we do finest: we’re gonna create our personal Figma widget! This one shall be impressed by Chris Coyier’s design quotes web site. We’ll take the API, feed it into the widget, then show random design quotes immediately in Figma.

Right here’s what we want

I don’t wish to be the bearer of dangerous information, however to be able to develop widgets, you should be on Home windows or Mac. Linux customers, I’m sorry, however you’re out of luck. (You can nonetheless use a VM if you wish to observe alongside.)

We’re gonna obtain the Figma Desktop utility. The best solution to get began is by producing a widget template, straight from the app.

Let’s create a brand new board by opening the widgets menu (ShiftI), switching to the Improvement tab, and creating a brand new merchandise.

Following that, Figma will immediate you to call the brand new widget and resolve whether or not it’s extra tailor-made in direction of design boards or FigJam boards too. The previous possibility is enough for the needs of this text.

And the customization doesn’t finish right here; Figma will even provide the possibility to begin with a pre-made counter widget or an iFrame-enabled different that additionally provides you entry to the Canvas and Fetch APIs (in addition to all different browser APIs). We’ll go along with the easy “Empty” possibility, however we’ll finally modify it ourselves to utilize the Fetch API.

You’ll then be prompted to save lots of your new widget challenge to a particular listing in your system. As soon as that’s executed, launch your terminal and direct it to that folder. Don’t run any instructions but — we’ll try this later and purposefully get an error with the purpose of studying extra concerning the Widgets API.

Designing the widget

We’re pulling the design straight from Chris Coyier’s design quotes web site. So, let’s go there and dive into by firing up DevTools.

The 2 key shortcuts that I’m utilizing listed below are Ctrl+Shift+C (or Cmd+Shift+C) to toggle the “Choose aspect” device, and Shift+Click on to alter the colour format to HEX code. We’re doing this to be taught concerning the colours, fonts, font weights and font sizes utilized in Chris’s web site. All this info is important to construct a closely-resembling widget in Figma, which shall be our subsequent step! You may seize the designed part and use it in your individual canvas.

I gained’t go into a lot element right here as this text’s important matter is constructing widgets by writing code. However I can’t stress sufficient how necessary it’s to take excellent care of your widgets’ model… CSS-Methods already has a plethora of design-oriented Figma tutorials; you gained’t remorse including them to your studying listing.

Creating the format for our widget

With design out of the best way, it’s time to take our programming fingers out and begin constructing the gears of our widget.

It’s very fascinating how Figma interprets its design constructing blocks to React-like parts. Body parts with the auto-layout characteristic, for instance, are represented because the <AutoLayout /> part in code. Along with that, we’ll be utilizing two extra parts: <Textual content /> and <SVG />.

Check out my Figma board… I’m exactly asking you to deal with the thing tree. It’s what we want to have the ability to translate our widget design to JSX code.

As you may see, our design quotes widget calls for three parts to be imported. That’s an honest variety of parts contemplating that the full API solely comprises eight layer-based nodes. However as you’ll quickly see, these modules are greater than enough to craft all types of layouts.

// code.tsx
const { widget } = figma;
const { AutoLayout, Textual content, SVG } = widget;

And with this, we have now all we have to go forward and construct the skeleton of our widget like we’d in React:

perform QuotesWidget() {
  const quote = `...`;
  const creator = `...`;

  return (
    <AutoLayout>
      <SVG />
      <AutoLayout>
        <Textual content>{quote}</Textual content>
        <Textual content>— {creator}</Textual content>
      </AutoLayout>
      <SVG />
    </AutoLayout>
  );
}

widget.register(QuotesWidget);

This code may be very complicated, to say the least. Proper now, we will’t inform the design layers aside. Fortunately, we’re in a position to simply clear up this challenge by way of using the identify property.

<AutoLayout identify={"Quote"}>
  <SVG identify={"LeftQuotationMark"} />
  <AutoLayout identify={"QuoteContent"}>
    <Textual content identify={"QuoteText"}>{quote}</Textual content>
    <Textual content identify={"QuoteAuthor"}>— {creator}</Textual content>
  </AutoLayout>
  <SVG identify={"RightQuotationMark"} />
</AutoLayout>;

And, after all, we nonetheless can’t see our citation mark SVGs, so let’s work on fixing that. The <SVG/> part settle for a srcproperty that takes the supply code for an SVG aspect. There isn’t a lot to say on this one, so let’s maintain it easy and bounce straight again to code:

const leftQuotationSvgSrc = `<svg width="117" top="103" viewBox="0 0 117 103" fill="none" xmlns="<http://www.w3.org/2000/svg>">
  // shortened for brevity
</svg>`;
const rightQuotationSvgSrc = `<svg width="118" top="103" viewBox="0 0 118 103" fill="none" xmlns="<http://www.w3.org/2000/svg>">
// shortened for brevity
</svg>`;

perform QuotesWidget() {
  return (
    <SVG identify={"LeftQuotationMark"} src={leftQuotationSvgSrc} />
    <SVG identify={"RightQuotationMark"} src={rightQuotationSvgSrc} />
  );
}

I believe we will all agree that every part is way clearer now! Once we identify issues, their function immediately turns into way more apparent to the readers of our code.

Previewing our widget in real-time

Figma gives a fantastic developer expertise when constructing widgets, together with (however not restricted to ) hot-reloading. With this characteristic, we’re in a position to code and preview modifications to our widget in real-time.

Get began by opening the widgets menu (Shift+I), switching to the event tab and clicking or dragging your new widget to the board. Unable to find your widget? Don’t fear, simply click on on the three-dot menu and import your widget’s manifest.json file. Sure, that’s all it takes carry it again to existence!

Wait, did you get an error message on the backside of your display?

If that’s the case, let’s examine. Click on on “Open console” and skim what it has to say. If the Open console button is gone, there’s another solution to open the debugging console. Click on on the Figma emblem, bounce to the widgets class and reveal the event menu.

That error is probably going attributable to the truth that we haven’t compiled our TypeScript to JavaScript but. We are able to try this within the command line by working npm set up and npm run watch. (or yarn and yarn watch ). No errors this time!

Yet one more impediment you would possibly hit is that the widget fails to re-render any time the code is modified. We are able to simply pressure our widget to replace utilizing the next context menu command: Widgets → Re-render widget.

Styling the widget

Because it at present stands, the seems to be of our widgets are nonetheless fairly removed from our closing purpose.

So how will we model Figma parts from code? Possibly with CSS like we’d do in a React challenge? Damaging. With Figma widgets, all the styling occurs by way of a set of well-documented props. Fortunate for us, this stuff are named virtually identically to their counterparts in Figma.

We’ll get began by configuring our two <AutoLayout /> parts. As you may see within the infographic above, prop names are fairly descriptive of their function. This makes it straightforward for us to leap straight into code and begin making some modifications. I gained’t be displaying the entire code once more, so please depend on the part names to information you the place the snippets belongs.

<AutoLayout
  identify={"Quote"}
  course={"horizontal"}
  verticalAlignItems={"begin"}
  horizontalAlignItems={"middle"}
  spacing={54}
  padding={{
    horizontal: 61,
    vertical: 47,
  }}
>
  <AutoLayout
    identify={"QuoteContent"}
    course={"vertical"}
    verticalAlignItems={"finish"}
    horizontalAlignItems={"begin"}
    spacing={10}
    padding={{
      horizontal: 0,
      vertical: 0,
    }}
  ></AutoLayout>
</AutoLayout>;

We simply made lots of progress! Let’s save and bounce again to Figma to see how our widget seems to be like. Bear in mind how Figma reloads widgets robotically upon new modifications?

But it surely’s not fairly there but. We should additionally add a background colour to the foundation part:

<AutoLayout identify={"Quote"} fill={"#ffffff"}>

Once more, check out your Figma board and spot how modifications could be mirrored virtually instantly again into the widget.

Let’s transfer alongside this information and magnificence the <Textual content> parts.

After looking on the Widgets API documentation, it’s once more clear that property names are virtually equivalent to their counterparts within the Figma app, as could be seen within the infographic above. We’ll even be utilizing values from the final part the place we inspected Chris’ web site.

<Textual content identify={'QuoteText'}
  fontFamily={'Lora'}
  fontSize={36}
  width={700}
  fill={'#545454'}
  fontWeight={'regular'}
>{quote}</Textual content>

<Textual content identify={'QuoteAuthor'}
  fontFamily={'Raleway'}
  fontSize={26}
  width={700}
  fill={'#16B6DF'}
  fontWeight={'daring'}
  textCase={'higher'}
>— {creator}</Textual content>

Including state to the widget

Oour widget at present shows the identical quote, however we need to pull from your entire pool of quotes at random. We should add state to our widget, which all React builders know is a variable whose change triggers the re-rendering of our part.

With Figma, state is created with the useSyncedState hook; it’s just about React’s useState, but it surely requires programmers to specify a distinctive key. This requirement stems from the truth that Figma should sync our widget’s state throughout all shoppers that could be viewing the identical design board, however by way of totally different computer systems.

const { useSyncedState } = widget;

perform QuotesWidget() {
  const [quote, setQuote] = useSyncedState("quote-text", "");
  const [author, setAuthor] = useSyncedState("quote-author", "");
}

That’s all of the change that we want for now. Within the subsequent part, we’ll determine the right way to fetch information from the Web. Spoiler Alert: it’s not so simple as it appears.

Fetching information from the community

Recall when Figma gave us the selection to begin with an iFrame-enabled widget. Though we didn’t go along with that possibility, we should nonetheless implement a few of its options. Let me clarify why we will’t merely name fetch() inside our widget code.

Once you use a widget, you might be working JavaScript code by yourself laptop that’s written by another person. Whereas all widgets are totally reviewed by the Figma workers, it’s nonetheless an enormous safety gap as everyone knows how a lot injury could be created by even one line of JavaScript.

Consequently, Figma can not merely eval() any widget code written by nameless programmers. Lengthy story brief, the group determined that one of the best resolution was working third-party code in a closely-guarded sandbox setting. And as you may need guessed, browser APIs are unavailable in such an setting.

However don’t fret, Figma’s resolution to this second drawback is <iframe>s. Any HTML code that we write in a file, ideally referred to as ui.html, may have entry to all browser APIs. You may be questioning how we will set off this code from the widget, however we’ll look into that later. Proper now, let’s bounce again into code:

// manifest.json
{
  "ui": "ui.html"
}
<!-- ui.html -->
<script>
window.onmessage = async (occasion) => {
  if (occasion.information.pluginMessage.kind === 'networkRequest') {
    // TODO: fetch information from the server

    window.father or mother.postMessage({
      pluginMessage: {
        // TODO: return fetched information
      }
    }, '*')
  }
}
</script>

That’s the overall template for widget-to-iframe communication. Let’s use it to fetch information from the server:

<!-- ui.html -->
<script>
window.onmessage = async (occasion) => {
  if (occasion.information.pluginMessage.kind === 'networkRequest') {
    // Get random quantity from 0 to 100
    const randomPage = Math.spherical(Math.random() * 100)

    // Get a random quote from the Design Quotes API
    const res = await fetch(`https://quotesondesign.com/wp-json/wp/v2/posts/?orderby=rand&per_page=1&web page=${randomPage}&_fields=title,yoast_head_json`)
    const information = await res.json()

    // Extract creator identify and quote content material from response
    const authorName = information[0].title.rendered
    const quoteContent = information[0].yoast_head_json.og_description

    window.father or mother.postMessage({
      pluginMessage: {
        authorName,
        quoteContent
      }
    }, '*')
  }
}
</script>

We’re leaving out error-handling to maintain this easy and to-the-point. Let’s bounce again into the widget code and see how we entry capabilities outlined within the <iframe>:

perform fetchData() {
  return new Promise<void>(resolve => {
    figma.showUI(__html__, {seen: false})
    figma.ui.postMessage({kind: 'networkRequest'})

    figma.ui.onmessage = async ({authorName, quoteContent}) => {
      setAuthor(authorName)
      setQuote(quoteContent)

      resolve()
    }
  })
}

As you may see, we’re first telling Figma to reveal entry to our hidden <iframe> and to set off an occasion with the identify "networkRequest". We’re dealing with this occasion within the ui.html file by checking occasion.information.pluginMessage.kind === 'networkRequest', after which posting information again to the widget.

However nothing is occurring but… We nonetheless haven’t referred to as the fetchData() perform. If we name it immediately within the part perform, the next error happens within the console:

Can't use showUI throughout widget rendering.

Figma is telling us to not name showUI immediately within the perform physique… So, the place ought to we put it? The reply to that’s one new hook and one new perform: useEffect and waitForTask. You would possibly have already got familiarity with useEffect for those who’re a React developer, however we’re gonna use it right here to fetch information from the server when the widget part mounts.

const { useEffect, waitForTask } = widget;

perform QuotesWidget() {
  useEffect(() => {
    waitForTask(fetchData());
  });
}

However this can lead to one more “error” the place our widget will maintain re-rendering with a brand new quote, endlessly. This occurs as a result of useEffect, by definition, triggers once more each time the widget’s state modifications, nay after we name fetchData. And whereas there’s a method to solely name useEffect as soon as in React, it doesn’t work on Figma’s implementation. From Figma’s docs:

Due to How Widgets Run, useEffect ought to deal with being referred to as a number of instances with the identical state.

Fortunately, there’s a easy workaround that we will reap the benefits of and name useEffect solely as soon as when the part first mounts, and it’s by checking whether or not or not the state’s values are nonetheless empty:

perform QuotesWidget() {
  useEffect(() => {
    if (!creator.size & !quote.size) {
      waitForTask(fetchData());
    }
  });
}

You would possibly run right into a scary “reminiscence entry out of bounds” error. It’s fairly frequent to see in plugin and widget growth. Simply restart Figma and it gained’t be there anymore.

You may need observed that typically, the quote textual content comprises bizarre characters.

These are Unicode characters and we should correctly format them in code:

<!-- ui.html -->
<script>
window.onmessage = async (occasion) => {
  // ...
  const quoteContent = decodeEntities(information[0].yoast_head_json.og_description);
};

// <https://stackoverflow.com/a/9609450>
var decodeEntities = (perform () {
  // this prevents any overhead from creating the thing every time
  var aspect = doc.createElement("div");

  perform decodeHTMLEntities(str) {
    if (str && typeof str === "string") "[^"]*"

    return str;
  }

  return decodeHTMLEntities;
})();
</script>

And voilà, our widget fetched a model new design quote each single time it’s added to the design board.

Whereas our widget fetches a contemporary quote upon instantiation, it could be way more sensible if we may do that course of once more however with out deleting it. This part shall be brief as the answer is kind of outstanding. With property menus, we will add interactivity to our widget with a single name to the usePropertyMenu hook.

Credit score: Figma Docs.
const { usePropertyMenu } = widget;

perform QuotesWidget() {
  usePropertyMenu(
    [
      {
        itemType: "action",
        propertyName: "generate",
	tooltip: "Generate",
        icon: `<svg width="22" height="15" viewBox="0 0 22 15" fill="none" xmlns="<http://www.w3.org/2000/svg>">
          <!-- Shortened for brevity -->
        </svg>`,
      },
    ],
    () => fetchData()
  );
}

With one easy hook we’re in a position to create a button that seems close to our widget when it’s chosen. That was the final piece that we would have liked so as to add to be able to full this challenge.

Publishing our widget to the general public

There’s not a lot use in constructing a widget if, effectively, nobody makes use of it. And whereas Figma grants organizations with the choice to launch non-public widgets for inner use, it’s way more frequent to launch these little packages to the world.

Figma has a fragile widget overview course of which will take up 5 to 10 enterprise days. And whereas the design quotes widget we constructed collectively is already within the widget library, I’ll nonetheless reveal the way it obtained there. Please don’t try and re-publish this widget once more as that may solely lead to elimination. However for those who gave it some vital alterations, go forward and share your individual widget with the neighborhood!

Get began by clicking the widgets menu (Shift+I) and switching to the Improvement tab to view our widget. Click on on the three-dots menu and press Publish.

Figma will immediate you to enter some particulars about your widget, resembling a title, description, and a few tags. We’ll additionally want a 128×128 icon picture and a 1920×960 banner picture.

After importing all these belongings, we nonetheless want a screenshot of our widget. Shut the publishing modal (don’t fear, you gained’t lose your information) and right-click on the widget to disclose an fascinating context menu. Discover the Copy/Paste asclass and choose Copy as PNG.

With that executed, let’s return to the publishing modal and paste the widget’s screenshot:

Scroll down and at last publish your modal. Have a good time! 🎉

Figma will attain out to you in a few days concerning the standing of your modal’s overview. Within the case of a rejection, you’ll be given the alternative to make modifications and submit once more.

Conclusion

We simply constructed a Figma widget from scratch! There are numerous issues not lined right here, resembling click on occasionsenter kinds, and way more. You may dig into the total supply code for the widget in this GitHub repo.

To those that aspire to take their Figma abilities to better ranges, I counsel exploring the Widgets neighborhood and utilizing what catches your eye as inspiration. Maintain constructing extra widgets, maintain sharpening your React abilities, and earlier than you even understand it, you’ll be instructing me the right way to do all this.

Additional assets

I needed to check with a number of documentation whereas I used to be making this widget. I assumed I’d share what I discovered to assist essentially the most.

Construct extra widgets:

Study widgets in better depth:

Widgets vs. plugins

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments