HTML to Frame: How a DOM Becomes Figma Auto Layout
How HTML to frame conversion works: DOM nesting, frame names, inferred Auto Layout, Fill and Center, 2 px verification, constraints and diagnostics.
EUREKA! · · 8 min read
Converting a web page into a picture is easy. Converting it into Figma frames that behave like a designer built them is the hard part. A frame that looks right but collapses the moment you edit a headline isn't much better than a screenshot.
This article explains, step by step, how HTML to Frames turns a DOM into nested Figma frames, how its Auto Layout engine decides what becomes a stack, and why it checks its own work before keeping it.
From DOM to frame tree
A web page is a tree: body contains sections, sections contain containers, containers contain cards, cards contain headings and buttons. A Figma file is also a tree: frames contain frames, text and vectors.
The basic idea of HTML to frame conversion is to map one tree onto the other:
- Each page and screen becomes a top-level frame. A Desktop, Tablet and Mobile import of one page produces three frames side by side.
- Elements that act as boxes become nested frames. Their backgrounds, borders, radii, shadows and clipping become frame properties.
- Text becomes text layers with mixed styles preserved, so a sentence with a bold link stays one text layer.
- SVG becomes editable vectors, and images become image fills.
- Pseudo-elements (
::before,::after), shadow DOM content and z-index order are carried over, so stacking matches what the browser drew.
The goal is a layers panel a designer can read, not a dump of every DOM node. If you need a more granular layer structure for inspection, the Detailed layers option (Pro) is there for that.
Frame naming
Top-level frames are named so you can find them in a large file:
example.com/pricing — Desktop (1920)
The name contains the domain and path (plus query, if any), with no protocol and no www, followed by the screen and its width, and it's capped at 60 characters. The source URL is also stored on the frame, which is what makes one-click Re-import possible.
Step 1: Build it pixel-exact first
The engine doesn't start by guessing Auto Layout. It starts with a version that's guaranteed to look right:
- The page is rendered in a real browser at the chosen width. For Desktop, that's Site width — a width the plugin measures from the page's actual design (1920 for full-bleed, the box width for boxed sites, 1440 for fluid sites).
- Every element's geometry and computed styles are measured.
- The frame tree is built with absolute positions, so every layer sits exactly where the browser put it.
This absolute version is the safety net. Everything after it is an improvement that has to prove itself.
Step 2: Infer Auto Layout, inside out
Next, the engine walks the frames from the innermost outward. For each frame, it looks at the measured geometry of its children and asks: can these be described as an Auto Layout stack?
It infers:
- Direction — are the children laid out in a vertical or horizontal stack?
- Wrapping — do they form wrapping rows, as in a CSS grid of cards or
flex-wrap? - Gap — is the spacing between children consistent enough to be one gap value?
- Padding — how far are the children from the frame's edges on each side?
- Alignment — are they aligned to the start, center or end on each axis?
Working inside-out matters: once a card's contents are a clean vertical stack, the card itself can be treated as a single item in the row of cards around it.
Crucially, the inference is based on what the browser actually rendered, not on parsing the CSS. Whether a row was built with flexbox, grid, floats or inline-block, the measured result is the same, and that's what the engine works from.
Step 3: Add responsive meaning
A stack with the right gap and padding is a start, but it doesn't yet behave like a responsive design. The engine also infers intent:
- Centred content → Center. If content sits centred in its parent, it's aligned Center, so it stays centred when the frame is resized.
- Max-width boxes stay centred. A content container with a maximum width inside a full-width section keeps its width and stays in the middle.
- Equal cards and flex-grow → Fill. Cards that share a row equally, or elements that grow to fill space, are set to Fill container.
- Logo … menu … icons → the gap item becomes Fill. In a typical header, the space between groups is what stretches. The engine makes that gap item Fill, so the logo stays left and the icons stay right as the header widens.
This is the difference between a frame that matches the page at one width and a frame you can actually resize.
Step 4: Verify every child (2 px tolerance)
Here's the part that keeps the design intact. After applying an Auto Layout plan to a frame, the engine checks the position of every child against the original pixel-exact layout. Each one must land within 2 px of where the browser put it.
- If every child holds, the plan is kept.
- If not, a simpler plan is tried — for example, a single stack without the more ambitious alignment or Fill settings.
- If no plan holds, the frame keeps its absolute positions.
The rule is simple: the design never breaks. You might get fewer Auto Layout frames on a tricky section, but you won't get a layout that silently shifts.
How often does it succeed? In our tests on real sites, Auto Layout was inferred on roughly 86–97% of frames — for example 93% on one product site and 88% on Linear and Stripe. Results depend on how the page is built, so treat these as measurements, not a guarantee.
Step 5: Constraints for frames that stay absolute
Frames that keep absolute positions don't get left behind. The engine gives them sensible constraints:
- Stretch — for elements that span their parent, such as a full-width background layer.
- Scale — for elements that should resize proportionally.
- Center — for elements centred in their parent.
- Min — pinned to the left or top.
- Max — pinned to the right or bottom.
So even an absolute frame behaves reasonably when you resize its parent.
Step 6: Diagnostics — why a frame stayed absolute
The results screen reports frames, layers and the Auto Layout share for the import, along with missing fonts and warnings. It also lists why specific frames stayed absolute. In practice, the sections that stay absolute tend to be the ones where children overlap, sit outside the normal flow, or are spaced too irregularly to be described as one stack.
These diagnostics are useful in two ways:
- For designers — you know which sections to convert by hand if you need them fully responsive.
- For developers — they're often a hint about layout code that's more complex than it needs to be.
CSS flexbox and grid to Auto Layout: a mapping table
Because the engine works from measured geometry, the mapping below describes the typical outcome, not a literal translation of CSS properties. For a deeper dive, see CSS flexbox and grid to Figma Auto Layout.
| CSS pattern | Typical Figma result |
|---|---|
display: flex; flex-direction: column | Vertical Auto Layout |
display: flex; flex-direction: row | Horizontal Auto Layout |
gap (or consistent margins) | Auto Layout spacing between items |
padding on the container | Auto Layout padding |
justify-content: center / align-items: center | Center alignment |
justify-content: space-between (logo … menu … icons) | Horizontal stack with the gap item set to Fill |
flex: 1 / flex-grow on items | Fill container |
flex-wrap: wrap | Wrapping Auto Layout rows |
display: grid with equal columns | Wrapping rows with equal Fill items |
max-width + margin: 0 auto | Fixed-width frame, centred in a Fill parent |
position: absolute / overlapping layers | Absolute position with constraints |
position: fixed / sticky headers | Kept fixed or sticky in Present mode |
| Irregular spacing that fails the 2 px check | Absolute positions, listed in diagnostics |
A worked example: a three-card pricing section
To make the steps concrete, picture a common section: a heading and subheading centred at the top, then three pricing cards in a row, each with a plan name, a price, a list of features and a button.
Here's how the engine would typically approach it:
- Pixel-exact build. Every element is placed at its measured position. The section already looks right.
- Innermost frames first. Each feature list becomes a vertical stack with a consistent gap. Each card becomes a vertical stack — name, price, list, button — with padding taken from the distance to the card's edges.
- The row of cards. The three cards sit side by side with equal widths and equal spacing, so the row becomes a horizontal stack with one gap, and each card is set to Fill so they share the width evenly.
- The header block. The heading and subheading are centred, so they become a vertical stack aligned Center.
- Verification. Every child of every frame is checked against its original position. If, say, a "Most popular" badge overlaps the top edge of the middle card, that card's plan may fail the 2 px check. The engine tries a simpler plan, and if that doesn't hold either, the card keeps absolute positions with constraints — and the results screen tells you which frame it was.
The outcome is a section you can resize: widen the frame and the cards grow together; edit a feature list and the card grows with it. With Components & hover states (Pro), the three cards may also come in as instances of one component, since they share a structure.
What this means in practice
When you open an imported page, you can:
- Edit a headline and the section grows, pushing content below it down.
- Change one gap value to tighten a card grid.
- Resize the frame and watch Fill items stretch while centred content stays put.
- Swap a card for a component instance — and with Components & hover states (Pro), repeated cards may already be components.
That's what separates a frame tree from a flattened image. The HTML to canvas comparison covers that contrast in more detail.
Tips for better Auto Layout results
- Import at the right width. Let Desktop use Site width, and add Tablet and Mobile with the Responsive set so you can check each breakpoint.
- Hide overlays. Turn on Hide cookie banners & popups so fixed dialogs don't overlap sections and force absolute positioning.
- Capture stable states. Animations are frozen at capture time, but for content that loads late, Extra wait (Pro) helps.
- Check the diagnostics before converting anything by hand. They tell you exactly which frames to look at.
- Use Reference screenshot (Pro) when you need to confirm the layers match the live page.
Learn more
- The full import flow: How to convert HTML to Figma
- All conversion features: features
- Every option, explained: docs
- Plans and limits: pricing
Get the plugin and import a page you know well. The quickest way to understand the engine is to resize the result and see what holds.
Frequently asked questions
- Does HTML to Frames read my CSS to create Auto Layout?
- It works from the browser's measured geometry rather than parsing CSS rules. The page is rendered in a real browser, every element is measured, and stacks, wrapping, gaps, padding and alignment are inferred from where things actually landed. That's why flexbox, grid or older layout techniques can all produce Auto Layout when the rendered result is regular.
- What does the 2 px verification do?
- After an Auto Layout plan is applied to a frame, the position of every child is compared with the original pixel-exact layout. Each child must be within 2 px. If any child moves further, a simpler plan is tried; if none holds, the frame keeps absolute positions. This is how the plugin ensures the design never breaks.
- Why did some frames stay absolute?
- A frame stays absolute when no Auto Layout plan passes verification, for example with overlapping children, elements outside the normal flow or irregular spacing. The results screen lists the reason for each such frame. These frames still get constraints such as Stretch, Scale, Center, Min or Max, so they behave sensibly when their parent is resized.
- How much of a page becomes Auto Layout?
- In our tests on real sites, Auto Layout was inferred on roughly 86 to 97 percent of frames, for example 93 percent on one product site and 88 percent on Linear and Stripe. The share depends on how the page is built, so treat these figures as measurements from our testing rather than a guarantee for every page.
- How are imported frames named?
- Top-level frames use the domain and path, plus any query, followed by the screen and width, such as example.com/pricing — Desktop (1920). The protocol and www are removed and names are capped at 60 characters. The source URL is stored on the frame as well, which lets you re-import it with one click later.
Stop redrawing the web.
Paste a link and get real, editable, responsive Figma layers in seconds. Free to start — 10 imports every month.