Help Needed: Replicating Selected Figma Element in Frontend

Hi everyone,

I’m working on replicating Figma elements in a React frontend. The goal is to replicate the exact position, size, and style of the selected element in Figma, using the data sent by the Figma plugin.

What I’ve Done

  • I’m receiving the data from the Figma then try to send it to frontend.
    const selection = figma.currentPage.selection;
    figma.ui.postMessage({ type: "selection-changed", selection});
  • In frontend, try to render with that data.
 useEffect(() => {
    window.onmessage = (event) => {
      const { type, selection} = event.data.pluginMessage;

      if (type === "selection-changed" && selection) {
        setElements(selection);
      }
    };

    return () => {
      window.onmessage = null;
    };
  }, []);

return (
    <div className="work-board">
      <div className="main-board">
        <div className="drop-board">
          {elements.length === 0 ? (
            <p>Select a frame or two to get started</p>
          ) : (
            elements.map((element) => renderVisualElement(element))
          )}
        </div>
...

But that is not rendering.

How can I fix this so that the selected Figma elements render exactly as they appear in Figma?

How are you trying to render the array of objects you receive in the UI?

Currently, your selection constant stores something like this: [{id: "0:1"}, {id: "0:2"}, …]. That is, no other information except the ID. So, either create and pass a new object, calling all the getters of the object’s properties first or export it to JSON and write your own function to convert this object to React elements, or export your selection to, for example, SVG or SVG_STRING, and pass that to the UI.

I can implement this by exporting the element using the Figma API. However, the requirement is that we should be able to edit the design without affecting the Figma file. So, I need the data of the selected element in order to replicate it on the frontend and edit it there.

I tried the code below in the Figma plugin, but I’m still encountering an issue. Is there a way to retrieve the data and replicate it? Also, for images, is it possible to get the image URL or the raw data?

const selection = figma.currentPage.selection;

    const serializedSelection = await Promise.all(
      selection.map(async (node) => {
        const element: any = {
          id: node.id,
          name: node.name,
          type: node.type,
          x: node.x,
          y: node.y,
          width: node.width,
          height: node.height,
          visible: node.visible,
          rotation:
            node.type === "FRAME" || node.type === "GROUP"
              ? (node as FrameNode | GroupNode).rotation
              : undefined,
          opacity: "opacity" in node ? node.opacity : undefined,
        };

        // Handle TEXT node properties
        if (node.type === "TEXT") {
          element.characters = (node as TextNode).characters;
          element.fontSize = (node as TextNode).fontSize;
          element.fontName = (node as TextNode).fontName;
          element.textAlignHorizontal = (node as TextNode).textAlignHorizontal;
          element.textAlignVertical = (node as TextNode).textAlignVertical;
          element.lineHeight = (node as TextNode).lineHeight;
          element.letterSpacing = (node as TextNode).letterSpacing;
          element.fills = (node as TextNode).fills;
        }

        // Handle RECTANGLE (and other shapes) node properties
        if (node.type === "RECTANGLE") {
          element.fills = (node as RectangleNode).fills;
          element.strokes = (node as RectangleNode).strokes;
          element.strokeWeight = (node as RectangleNode).strokeWeight;
          element.strokeAlign = (node as RectangleNode).strokeAlign;
          element.cornerRadius =
            "cornerRadius" in node ? (node as RectangleNode).cornerRadius : 0;
          element.dashPattern = (node as RectangleNode).dashPattern;

          // Handle IMAGE fill if available
          const fills = (node as RectangleNode).fills;
          if (Array.isArray(fills) && fills.length > 0) {
            const imageFill = fills.find((fill) => fill.type === "IMAGE");
            if (imageFill) {
              const image = figma.getImageByHash(imageFill.imageHash);

...

If you got all the required properties of the object and wrote a function to convert it to React elements, then everything should be fine.

As for the code snippet you provided, I would get all the properties using a recursive function using loops.

You can get the URLs of the images using the REST API. The raw data can be obtained using the exportAsync function I mentioned above.

To use Figma API, I need fileId, right?
But, in Figma plugin, how can I get fileId?
figma.fileKey is returning undefined.

If you mean REST API, then yes, some endpoints require a file key, including the GET image and GET image fills endpoints. But if you want to get JSON of the object, you can use exportAsync function from Plugin API.