Open-source project
react-figma/react-figma avatar
react-figma/react-figma

React Figma's newest tag is from June 2024 and its engine range starts at Node 10

⚛️ A React renderer for Figma

2,691 stars135 forksTypeScriptMIT

At a glance

What is it?
React Figma is a React renderer that writes a component tree into a Figma document through the plugin API, with Yoga layout, RPC across two threads, and hydration. The manifest is where the honest picture sits: a 2024 release line, a 2026 branch, an engine range from Node 10 to before 22, a build script that sets a Babel variable and then invokes tsc, and a test suite that runs against a stub rather than Figma.
Who is it for?
Reach for it when you want one component tree to become both a Figma document and a live app, and you are willing to accept that the renderer only runs inside a Figma plugin sandbox. Check three things first.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The newest tag is from June 2024 and the branch moved in April 2026

The release history is lumpy. The newest tag is v0.31.0, dated 2024-06-03, and its release note is a single clause about fixing supported node versions. Before that the project jumps back to 2022-03-09, where v0.24.0 and v0.23.0 were published about fifty minutes apart on the same day, one adding support for Page backgrounds and the other adding a useStyleByKey hook. The version in the package manifest matches the newest tag exactly at 0.31.0, so there is no drift between the published number and the committed one. The gap is between the tag and the branch. The default branch is master and its last push is dated 2026-04-14, which puts roughly sixteen months of unpushed-to-a-release work between the two dates, and no tag describing it. Anyone installing from npm gets the June 2024 tree, and anyone reading master is reading something newer that has never carried a version number.

The engine range starts at Node 10 and stops before Node 22

The manifest declares its supported runtime as `>=10.0.0 <22.0.0`. That range admits Node 10, which predates the project's own tooling by years, and excludes 22 and everything after it. The upper bound is the part that matters in practice, because 22 is where the long-term line landed and the floor is the part nobody will hit. The contradiction inside the project is that the newest release is titled after fixing supported node versions, and the range that came out of it still starts at a double digit major. The type definitions do not help either: the dev dependency on Node types is a caret range starting at 12.7.8, so the compile time view of Node is a major version older than the oldest runtime the manifest claims to support. Nothing in the manifest states whether the ceiling exists because of the plugin sandbox, the Figma typings, or a build tool, and a project that renders into a design tool has little room to negotiate the host runtime anyway.

The build sets a Babel variable and then runs tsc

The library build is two chained commands. The first deletes the output directory with rimraf, and the second sets an environment variable and compiles:

code
cross-env BABEL_ENV=production tsc -p tsconfig.json

Babel is not in that command. The compiler being invoked is the TypeScript one, and TypeScript does not read BABEL_ENV, so the variable is aimed at a tool that is not on the line. Babel is present elsewhere in the project, in the Jest configuration, where the preset is a TypeScript preset running in its js-with-babel mode and a setup file is loaded from the repository root. So there are two transpilation paths in one package, one of them used for tests and one of them bypassed at build time while still receiving its settings. The build script also passes no emit options of its own, so whatever the compiler does about declarations comes from tsconfig.json alone. Two declaration files sit at the repository root rather than inside the source directory, which suggests the shape of the published types is decided by where files happen to be on disk rather than by a generated output tree.

Two pre-commit mechanisms, and a test suite aimed at a stub

The manifest declares two different things under the same name. There is a pre-commit key whose value is an array of three script names, prettify, tsc and test, which is the shape an older hook installer expects. There is also a dev dependency called pre-commit pinned to a caret range in the version one series, which is the npm client for the same idea. Both are present at once, so a contributor installing the repository gets one mechanism wired through scripts and another installed as a package, and nothing in the manifest says which one actually runs. The test setup is where the more consequential choice sits. Jest is configured with a TypeScript preset in its Babel mode, a root setup file, and a dev dependency named figma-api-stub at version 0.0.55. That stub stands in for the entire Figma plugin API at render time, so a passing suite is evidence about the stub's fidelity and not about Figma. The network is replaced too, since a fetch mock is also in the dev dependencies, which means the data-fetching example is exercised without a real request. For a renderer whose entire job is talking to one vendor's runtime, that is the distinction that matters.

Figma typings at 1.64.0 beside Jest 24 and React 16.8.6

The dependency list splits into two generations. The Figma typings are pinned to an exact version, 1.64.0, with no caret, which is the practice you use when a vendor API moves under you. Everything around them is years older: React is held at 16.8.6 exactly, Jest and babel-jest are at the version 24 series, the Jest type definitions are the 24 series, Prettier is at 1.18.2, and the webpack plugins in the list are the version 3 generation. The React type definitions are the 16.9 range while the runtime is 16.8.6, so the types describe a patch level the runtime never took. Reading the list as a timeline, the author pinned the vendor surface in place and let everything else drift to whatever was current when the project was last built out. The Yoga layout types sit in the same era at a 1.9 range. The HMR story the summary advertises therefore depends on that same old webpack stack, with an inline source plugin at 0.0.10, a file loader, a css loader and a shared webpack config package still at 0.0.7. Two small fields in the same manifest reinforce the impression of a hand-kept package. The keywords array holds three entries, figma, react and figma-plugins, which is the entire discoverability surface, and the repository url is written in the git+ssh://[email protected]/ form that predates the current shorthand.

Six example directories the project description never lists

The examples section names ten directories and one external repository. The tree holds sixteen. The six that exist on disk and are not named in the overview are auto-layout, basic-animation, dynamic-layout, hyperlink, images and page-background. Two of them are the interesting omissions. Animation is not mentioned anywhere in the visible description even though a directory named for it ships, and page-background support is the subject of the v0.24.0 release note from 2022 yet has no entry in the list of examples. So the newest capabilities are the least documented in the one place a reader would look. The listed ten cover the basics, hot module replacement, a design system, interactivity, plugin UI interaction, data fetching, styled-components, component variants, MDX and local styles. MDX is the one that changes what the input is, since a markdown file with embedded components becomes Figma nodes rather than a JavaScript module. The documentation index has the same shape. It links render, Page, Frame, View, Text and Image, and then stops with an ellipsis, so the component surface is explicitly unbounded. Frame and Image are named there and appear in none of the three code samples in the visible text. The compatibility claim reaches past React DOM as well, naming the react-native, react-sketchapp and react-primitives APIs at once, and the type packages for two of those sit in the dev dependencies at a 0.63 range and a 1.9 range respectively.

The two Text examples disagree about where the string lives

Two different code samples appear in the visible description and they do not agree on the text API. The first builds a tree from Page, View and Text, and puts the string inside the element as a child:

javascript
import * as React from 'react';
import { Page, View, Text } from 'react-figma';

export const App = () => {
    return (
        <Page name="New page" isCurrent>
            <View>
                <View style={{ width: 200, height: 100, backgroundColor: '#dd55aa' }} />
                <Text style={{ color: '#ffffff' }}>text</Text>
            </View>
        </Page>
    );
};

The third sample imports Page, Rectangle and Text instead, drops the isCurrent flag, and passes the same string as a characters attribute on a self-closing element. The container element changes from View to Rectangle in the same breath. Whichever form is current, one of the two samples in the project's own front page is teaching an older shape. The two thread setup samples have their own asymmetry: the main thread calls `figma.showUI(__html__, { visible: false })` and then `setupMainThread()`, while the UI thread imports the rpc entry point for its side effects and calls render. The plugin UI is therefore created hidden, and the interaction story depends on the separate ui example.

Empty slots where the logo and the sponsor logos should be

Several decorative parts of the project description are empty anchors. The slot under the summary is an aligned paragraph with nothing inside it. The BrowserStack section is a link with no content. The sponsoring section lists six backer slots and six sponsor slots, each an anchor element wrapping nothing at all, so twelve logos are declared and zero are shown. That pattern extends into the repository. Publishing is driven by a hand-maintained .npmignore rather than by a package manifest field, the build deletes and recreates a dist directory that the manifest never declares, and two TypeScript declaration files sit at the root beside the README instead of inside the source tree. Website deployment is configured in a file called now.json, a name from a hosting service that has since been renamed, and the CI badge points at CircleCI. The file names at the root are inconsistent about case too, with a contributing guide written in lowercase and a code of conduct written in uppercase in the same directory. Each of these is small on its own. Together they describe a project whose publishing and packaging story is assembled by hand rather than derived.

Editorial conclusion

Reach for it when you want one component tree to become both a Figma document and a live app, and you are willing to accept that the renderer only runs inside a Figma plugin sandbox. Check three things first. The Node range declares support from 10 up to but not including 22, so a modern toolchain sits outside the declared range even though the last release was specifically about supported node versions. The build step sets a Babel environment variable and then runs the TypeScript compiler, which does not read it. And the tests run against a Figma API stub at version 0.0.55, so a green suite is a statement about the stub rather than about Figma. With the newest tag two years behind the last push, read the commit history before trusting any example.

Frequently asked questions

What is the newest published version of React Figma?

v0.31.0, tagged 2024-06-03, with a release note about fixing supported node versions. The package manifest carries the same version, 0.31.0.

Which Node versions does React Figma declare support for?

The manifest declares `>=10.0.0 <22.0.0`, so Node 10 upward is admitted and Node 22 and later are excluded.

Does React Figma run against the real Figma API in its tests?

No. The Jest configuration loads a setup file and the dev dependencies include figma-api-stub at version 0.0.55, which stands in for the plugin API during tests.

How are the two threads of a React Figma plugin wired together?

The main thread calls `figma.showUI(__html__, { visible: false })` and then `setupMainThread()` from react-figma/rpc. The UI thread imports that same rpc entry point for its side effects and calls render with the component tree.

Is React Figma a code generator?

It says it is not one. The project description states plainly that it is not a code generator, and describes it as a renderer that uses React components as a source for designs.

Official sources

  1. License: MIT
  2. Project website
  3. react-figma/react-figma on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/react-figma-react-figma.svg)](https://hysenlabs.com/projects/react-figma-react-figma)