Why icons go missing when you import a web page into Figma
Everything imports except the icons. Empty boxes, black squares, or little rectangles where the chevrons were. There are four causes, and which one you have decides whether it is fixable.
You convert a page into Figma and everything arrives except the icons. Where the chevrons and the search glass and the little external-link arrows used to be, there are empty squares, or black blobs, or nothing at all.
This is not one bug. Icons on the web are drawn three completely different ways, and each one breaks differently. Knowing which kind you are looking at tells you whether it can be fixed and how.
The three kinds of icon, and how each one fails
1. Inline SVG
The easy case. The icon is written directly into the HTML as an <svg> element with its paths right there. Any converter that reads the DOM can see the geometry and hand Figma a vector.
When these fail it is usually because the SVG relies on something the converter flattened: a <use> reference to a symbol defined elsewhere, a CSS filter, or a currentColor fill that has no colour once the element is out of its cascade.
2. SVG sprites
One file holds every icon as a <symbol>, and each place an icon appears contains only a reference:
<svg class="icon"><use href="/icons.svg#chevron-down" /></svg>
Efficient on the web, invisible to a naive converter. The element in the DOM has no paths in it. Read it literally and you get an empty <svg>, which is why sprites so often arrive as blank boxes of the right size.
Resolving them means following the reference, fetching the sprite file, finding the symbol by its id, and inlining the geometry — and doing that for a cross-origin sprite file means the fetch has to be allowed at all.
3. Icon fonts
The icon is a character in a font. Font Awesome, Material Icons, and every in-house icon font work this way: an element with a class, a ::before pseudo-element, and a content property holding a codepoint in the Unicode private use area.
.fa-search::before { content: "\f002"; }
Two things go wrong. First, the icon lives in a pseudo-element, which is not in the DOM — walk the element tree and it is not there. Second, if a converter does capture it as text, it comes into Figma as the literal character, and unless the icon font is installed on your machine Figma renders whatever fallback it has: an empty box, or a random glyph.
This is the source of the classic symptom where an imported page is full of little rectangles where the icons should be.
The fourth case: CSS mask icons
Worth its own mention because it is increasingly common and fails in a way that looks like success. The element has no content at all; it has a background colour and a mask:
.icon {
background-color: currentColor;
-webkit-mask-image: url(/icons/search.svg);
mask-size: contain;
}
The shape lives in the mask image, the colour lives in the element. A converter that reads the background gets a solid rectangle in the icon's colour. That is why these often arrive as filled black or coloured squares rather than as nothing — the colour is right and the shape is gone.
VitePress-based documentation sites use this pattern heavily, which is how we first ran into it: a user reported that every icon on a docs site had imported as a black square.
Why converters miss them
Because handling all four means doing four different things, and three of them require work beyond reading the DOM:
- Sprites need the referenced file fetched and the symbol extracted.
- Icon fonts need pseudo-element styles read, the codepoint resolved, and the glyph rendered to a vector rather than passed along as text.
- Mask icons need the mask image fetched, and the element's colour applied to the resulting shape rather than to a rectangle.
A converter that only walks the DOM and copies what it finds will get case one and quietly fail the rest. That is the common behaviour, not an unusual one.
How to tell what you are dealing with
Open the page, right-click the icon, and inspect it. Thirty seconds tells you which case you are in:
| What you see in the inspector | Kind | How it usually fails |
|---|---|---|
<svg> with <path> inside | Inline SVG | Usually fine |
<svg> with <use href="…#id"> | Sprite | Empty box |
<i> or <span> with an icon class and no children | Icon font | Missing glyph rectangle |
Element with mask-image in computed styles | CSS mask | Solid coloured square |
What Snapture does with each
All four are handled, and it is worth being specific about how, because "we support icons" is the kind of claim every tool makes.
- Inline SVG is passed through as vector geometry. Where an SVG is complex enough that Figma's importer would choke on it — nested masks, filters,
foreignObject— it is rasterised instead, which is a deliberate downgrade rather than a silent failure. - Sprites are resolved by following the
<use>reference, fetching the sprite, and inlining the referenced symbol's geometry with the correct viewBox. - Icon fonts are detected by reading the pseudo-element's computed
content, and the glyph is rendered to a shape rather than passed to Figma as a character. The result does not depend on you having the icon font installed. - CSS mask icons are resolved by fetching the mask image and applying the element's own colour to the resulting shape, so a mask icon arrives as the icon in its real colour rather than as a filled rectangle.
In the measurement run published on the proof page, Linear's homepage produced 215 vector nodes and Stripe's 153 — most of that is icon work, and it is the difference between a file you can edit and a file with holes in it.
If your icons are already broken in a file
There is no repair for a rasterised black square; the shape information never made it into the file. Re-import with a tool that resolves the case you are hitting.
The one exception is icon fonts. If icons came in as text characters and you have the icon font installed locally, Figma will render them correctly on your machine — but they will break for anyone who opens the file without that font, so it is worth re-importing anyway rather than shipping a file that only works for you.
Try it on your own pages Five free captures, every feature included. No card, no account.English · 한국어 · 日本語 · 简体中文 · 繁體中文 · Español · Português · Français · Deutsch · Русский · Italiano · Bahasa Indonesia