Design to code
Figma auto layout to flexbox: a practical CSS mapping
Map Figma auto layout to flexbox: direction, gap, padding, alignment, Hug, Fill and Fixed, with a full table, a worked card example and common pitfalls.
Figma auto layout maps closely to CSS flexbox: a horizontal or vertical auto layout frame is a flex container with flex-direction: row or column, the gap is gap, the padding is padding, and the alignment box sets justify-content and align-items. The parts that need care are sizing (Hug, Fill and Fixed) and the defaults, which differ between the two.
Below: the full mapping, the alignment and sizing rules behind most bugs, a worked example, and how to hand this to a coding agent.
The mapping table
| Figma auto layout | CSS |
|---|---|
| Horizontal | display: flex; flex-direction: row |
| Vertical | display: flex; flex-direction: column |
| Wrap | flex-wrap: wrap |
| Gap (a number) | gap |
| Gap Auto: Between | justify-content: space-between |
| Gap Auto: Around | justify-content: space-around |
| Gap Auto: Evenly | justify-content: space-evenly |
| Padding | padding |
| Alignment box | justify-content and align-items, depending on direction |
| Baseline alignment | align-items: baseline |
| Hug contents | Content size: the flex item default, or width: fit-content |
| Fill container | flex: 1 and min-width: 0 on the main axis, align-self: stretch on the cross axis |
| Fixed width or height | width or height, plus flex-shrink: 0 |
| Minimum and maximum width or height | min-width, max-width, min-height, max-height |
| Ignore auto layout | position: absolute on the child, position: relative on the frame |
| Grid | display: grid, a different mapping |
The Auto gap options line up exactly. Between puts no space at the edges, like space-between. Around makes each gap twice the edge space, which is what space-around does with its half-size space at each end. Evenly spreads equal space across gaps and edges, like space-evenly. MDN’s basic concepts of flexbox describes each value.
Direction decides what alignment means
Figma’s alignment box shows nine positions, from top left to bottom right, whatever the direction. CSS has no such box: it has a main axis (the direction of the flow) and a cross axis, each with its own property.
justify-contentaligns along the main axis.align-itemsaligns along the cross axis.
So the same Figma position gives different CSS depending on direction:
| Figma position | Horizontal frame | Vertical frame |
|---|---|---|
| Top left | justify-content: flex-start; align-items: flex-start |
justify-content: flex-start; align-items: flex-start |
| Top center | justify-content: center; align-items: flex-start |
justify-content: flex-start; align-items: center |
| Right | justify-content: flex-end; align-items: center |
justify-content: center; align-items: flex-end |
| Bottom center | justify-content: center; align-items: flex-end |
justify-content: flex-end; align-items: center |
The other trap is the default. A new flex container has align-items: stretch, so its children stretch across the cross axis. In a vertical frame, a button that hugs its label in Figma becomes full width in CSS. Set align-items explicitly on every container, or give that child align-self: flex-start.
Hug, Fill and Fixed in CSS
Sizing is where most “almost right” layouts come from. Each Figma setting applies to one axis, so translate width and height separately.
Hug contents
A flex item sizes to its content on the main axis by default (flex: 0 1 auto), so a hugging child in a row often needs nothing. Three cases need code:
- A container that hugs.
display: flexmakes a block-level box that takes the full width of its parent. Usewidth: fit-content, ordisplay: inline-flex. - A hugging child on the cross axis. It stretches because of
align-items: stretch. Usealign-self: flex-start, or the alignment you want. - A hugging child in a crowded row. Flex items can shrink by default (
flex-shrink: 1). Addflex-shrink: 0when it must keep its size.
Fill container
On the main axis, Fill means “take the remaining space”: flex: 1, which expands to flex: 1 1 0% (see MDN on the flex shorthand). Add min-width: 0 in a row, or min-height: 0 in a column. The automatic minimum size of a flex item is its min-content size, so a long word or a wide table inside a filling child pushes it wider than its share instead of letting it shrink or truncate.
On the cross axis, Fill is align-self: stretch, which is also the default of align-items. It only works when the item has no fixed size on that axis: with a set height in a row, the item keeps its height.
Fixed
A fixed width is width (or flex-basis) plus flex-shrink: 0. Without it, the default flex-shrink: 1 lets the browser squeeze your 120 px button when the row runs out of space, which a Fixed layer in Figma never does.
Padding, strokes and box sizing
A Figma frame’s width is its outer width: the padding sits inside it. CSS uses content-box by default, where width covers the content only and padding and border are added on top. A card set to 320 px with 16 px of padding is then 352 px wide. Use border-box everywhere:
*, *::before, *::after {
box-sizing: border-box;
}
With border-box, the width includes padding and border, as in Figma.
Strokes need one more decision. Figma lets you include an inside stroke in the layout or exclude it. A CSS border always takes space, so it matches “included”. For “excluded”, draw the line without moving anything: an outline, which never takes up space, or box-shadow: inset 0 0 0 1px, which does not change the size of the box.
Gap behaves the same in both tools: space between items only, none before the first item or after the last. With wrap on, gap accepts two values: the gap between rows, then the gap between columns.
A worked example: a card
A card specified in Figma:
- Card: Vertical, padding 16, gap 12, width Fixed 320, alignment Top left.
- Header: Horizontal, gap 8, alignment Left, width Fill.
- Title: text, width Fill, truncated on one line.
- Badge: Hug.
- Button: Hug.
In CSS, with spacing tokens:
.card {
display: flex;
flex-direction: column;
align-items: flex-start; /* Top left: children hug instead of stretching */
gap: var(--space-3); /* 12 */
padding: var(--space-4); /* 16 */
width: 320px; /* Fixed */
}
.card-header {
display: flex;
align-items: center; /* Left: vertically centered */
gap: var(--space-2); /* 8 */
align-self: stretch; /* Fill the width of the card */
}
.card-title {
flex: 1; /* Fill */
min-width: 0; /* lets a long title shrink */
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.card-badge {
flex-shrink: 0; /* Hug, never squeezed */
}
<article class="card">
<div class="card-header">
<h3 class="card-title">Quarterly report for the north region</h3>
<span class="card-badge">Draft</span>
</div>
<p>Due Friday, shared with 4 people.</p>
<button>Open</button>
</article>
The align-items: flex-start on the card is the line most translations miss: without it, the button stretches to 288 px. Tokens for gap and padding keep the numbers tied to your scale. See design tokens an AI coding agent can follow.
Handing auto layout to a coding agent
A coding agent translates auto layout well when it gets the properties as text instead of guessing them from a picture. For each frame, give the direction, gap, padding, alignment, and the sizing of each child on both axes. Then state the mapping:
Implement this card with flexbox. Mapping: Horizontal or Vertical = flex-direction
row or column, gap = gap, padding = padding, Fill = flex: 1 plus min-width: 0 on the
main axis and align-self: stretch on the cross axis, Hug = content size with
flex-shrink: 0, Fixed = width plus flex-shrink: 0. Set align-items explicitly on
every container. Use box-sizing: border-box and the spacing tokens in src/styles/tokens.css.
The mapping also works the other way. In agentappbuilder, the Design panel of the canvas uses Figma’s names on HTML prototypes: for an element laid out with flexbox, Auto layout sets the direction, the gap, the alignment on a 3 x 3 grid, space between and wrap, next to padding, fill, stroke and corner radius. Each change is written as an inline style on the element, and your agent receives the list of properties you changed, with the values before and after, to implement in your code. See edit a frame for the panel, implement your edits for the prompt, and edit a prototype visually, then let the agent code it for the whole workflow.
Summary
Treat each auto layout frame as a flex container: direction becomes flex-direction, gap and padding stay as they are, and the alignment box splits into justify-content and align-items according to direction. Translate sizing per axis: Hug is content size, Fill is flex: 1 with min-width: 0 or align-self: stretch, Fixed is a size with flex-shrink: 0. Set box-sizing: border-box and explicit alignment, and most “almost right” layouts go away.
Frequently asked questions
Is Figma auto layout the same as CSS flexbox?
Close to it. Horizontal and vertical auto layout behave like a flex container with flex-direction row or column, gap and padding. Sizing and default alignment differ, so map Hug, Fill and Fixed explicitly.
What is Fill container in CSS?
On the main axis, flex: 1 with min-width: 0 (min-height: 0 in a column). On the cross axis, align-self: stretch, which only works when the item has no fixed size on that axis.
What is Hug contents in CSS?
Content size. A flex item already sizes to its content on the main axis, and flex-shrink: 0 stops it from shrinking. A container on its own needs width: fit-content or display: inline-flex, or it takes the full width.
Try it on your own app
Tell Claude Code one sentence. It creates the project and gives you a link to see your screens.
Tell Claude Code:
Connect this project to agentappbuilder.com and show me its screens.