FISYCO

Public beta
The gapImpactHow it worksProductSecurity
Sign in

Figma icons to React components, end to end

7 min read

Engineering
A grid of icon tiles on a Figma-like canvas flowing into a code file card and a pull request card with a check mark

An icon set lives in Figma, and the product uses it in React. Between the two there is usually a person: someone exports SVGs, renames files, pastes them into the repository and hopes nothing else changed. This guide follows Figma icons to React components along the whole path: from an icon component in Figma to a merged pull request, with what each step produces.

We build FISYCO, which automates this path. The steps below work with any tooling, and the examples are real output of our generator for three icons.

Key takeaways
- Treat icons as data: read them from Figma by node ID, not by file name, so a rename is a rename and not a new icon.
- Pick one delivery format per product: React components, one SVG sprite, or a package of SVG files. Each has a clear best case.
- Clean every SVG twice: sanitise it when it enters your system, optimise it when you generate code.
- Deliver changes as a pull request with a readable diff, and trigger it from a library publish in Figma.

Step 1. Decide what counts as an icon

Figma files mix icons with everything else, so the first decision is scope. Point the export at the pages and sections where the icon components live, not at the whole file. A section per category, such as Navigation, Status or Social, keeps the scope readable, and the section name can become part of the output path later.

Read components, not loose frames. A component keeps its node ID when it's renamed or dragged within the file; its name is just text. Everything downstream depends on that ID: it's how you tell "renamed" from "deleted and added".

Step 2. Export SVG from Figma

Figma's REST API renders nodes as images through GET /v1/images/:file_key with format=svg (Figma REST API: images). The call takes a list of node IDs and returns a temporary URL for each SVG. Large sets go in batches: we request 100 nodes per call and cap each SVG at 1 MB.

Figma's plan comparison marks only the Variables REST API as Enterprise-only, so exporting icons doesn't hit that limit (why variables need a workaround).

Step 3. Clean the SVG on the way in

An SVG is a document, and a document from outside can carry things you don't want in your codebase. For example: <script>, event handlers such as onload, <foreignObject> or links with a javascript: URL. Remove them before the file is stored or previewed. We sanitise every SVG before it's written to our registry, and all generated code is built from that cleaned copy.

The same step is the right place for quality checks that don't change the file: a missing viewBox, empty paths and groups, colours that won't follow the text colour. Report them to the designer rather than fixing them silently.

Step 4. Know what changed

Compare the new export with the last one by node ID and content hash:

Moving an icon out of the selected pages or sections counts as removed. This table is what makes the pull request reviewable. Without it, every export looks like "all icons changed", reviewers approve on trust, and production quietly drifts from the design. With it, a reviewer sees three modified icons and one rename.

Names need one more rule. Normalise the Figma name to something code can use: lower case, spaces to hyphens, only a-z0-9-. When two icons normalise to the same name, flag the conflict and suggest name-2, instead of letting one file overwrite the other.

Step 5. Pick a delivery format

There are three sensible ways to ship icons to a React codebase.

React components

This is the output for an arrow icon, generated with TypeScript, named exports, a 1em size and one colour replacement, #1A1A1A → currentColor:

import * as React from "react";
import type { SVGProps } from "react";
const ArrowRight = (props: SVGProps<SVGSVGElement>) => <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="none" viewBox="0 0 24 24" {...props}><path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 12h14m-6-6 6 6-6 6" /></svg>;
export { ArrowRight };

Three details matter. 1em makes the icon follow the font size around it. currentColor makes it follow the text colour, so hover and disabled states come for free. And spreading props onto the <svg> lets a consumer pass aria-label, className or a different size.

The colour replacement is the step people skip. Designers draw icons in a real colour, and without the replacement every icon ships with that colour baked in. It suits single-colour icons; multi-colour icons keep their fills.

For accessibility, pass aria-hidden="true" when an icon sits next to a text label, and role="img" with an aria-label when the icon carries meaning on its own (MDN: img role).

SVG sprite

A sprite is one hidden SVG with a <symbol> per icon:

<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
<symbol id="fsc-arrow-right" viewBox="0 0 24 24">…</symbol>
<symbol id="fsc-check-circle" viewBox="0 0 24 24">…</symbol>
</svg>

A page includes it once and references icons with <svg><use href="#fsc-arrow-right" /></svg>. The prefix, fsc- here, keeps symbol IDs from colliding with other IDs on the page.

Package

A package keeps the plain files and adds a manifest, so any consumer can read the set:

src/icons/
├── icons/
│   ├── arrow-right.svg
│   ├── check-circle.svg
│   └── github.svg
├── index.json
└── package.json

The manifest maps each icon's ID and name to its file. That ID is the Figma node ID behind the icon, so a consumer can track it across renames too.

Step 6. Optimise when you generate

Optimisation belongs to generation, not to storage. Run SVGO with its default preset when you build components. Prefix IDs inside each icon too, so two icons with a <clipPath id="a"> don't break each other on one page. Keep the stored SVG unoptimised: if the optimiser changes, you regenerate from the original instead of optimising twice.

Step 7. Deliver as a pull request

Write the generated files on a branch and open a pull request against the repository. A good icons PR:

  • touches only the files this delivery owns, so it can also delete icons that were removed in Figma without touching anything else;
  • lists added, modified, renamed and removed icons in the description;
  • carries a label for added, modified or removed icons, so release notes can pick it up.

Then let the normal review happen. A reviewer checks the diff of three icons, not a regenerated folder of two hundred.

Step 8. Trigger it from Figma

The last manual step is starting the export. Figma sends a LIBRARY_PUBLISH webhook when a library is published (Figma webhooks), and the event lists the components that were created, modified and deleted (created_components, modified_components, deleted_components). Use it to start a sync, and use the list to download only the changed icons instead of the whole set.

With that in place, a publish in Figma opens a pull request without anyone exporting files by hand.

Build it or run it

You can build this pipeline yourself: the Figma API, SVGO and a script that writes a branch cover most of it. The parts that take longest to get right are the unglamorous ones: stable IDs, rename detection, deleting only what you own, and a diff a reviewer can trust.

If you'd rather not maintain that, FISYCO runs the same steps. It scopes by pages and sections, sanitises every SVG and delivers components, a sprite or a package. After each library publish it opens a pull request. The same approach works for design tokens, see design tokens from Figma to code.

Connect your Figma icon library and get the first pull request today.
#Icons#Figma#Pull requests
KK

Written by

Kirill Karpov

Founder, FISYCO

Kirill Karpov is the founder of FISYCO, a design system assurance tool that keeps Figma and production code in sync.

Get new articles by email

Design systems, tokens and design-to-code delivery. No spam, and you can leave in one click.

By subscribing you agree to get blog emails from FISYCO. Details are in the privacy policy.

Keep your design system and your code in sync

FISYCO connects Figma libraries and your codebase, finds drift and opens the fix as a pull request.

Start for free

Related articles

6 min read

Engineering

Style Dictionary in practice: design tokens to CSS, SCSS and TypeScript

A working Style Dictionary 5 setup for DTCG tokens, tested on a real build: references, modes, units, and a rename experiment that breaks CSS silently.

6 min read

Engineering

How to ship Figma variables to developers without an Enterprise plan

The only official API for Figma variables is Enterprise-only. Here are the three ways variables leave Figma today and where each one stops.

6 min read

Engineering

Design tokens from Figma to code without manual exports

A workflow that keeps tokens in Figma and code in sync: name tokens by purpose, compare instead of copying and deliver every change as a pull request.

Figma icons to React components, end to end | FISYCO