learn.aathan.in

Figma to Tailwind: The Complete Conversion Workflow

How to turn a full Figma design into clean HTML + Tailwind CSS — reading Dev Mode, mapping tokens and Auto Layout to Tailwind, and a worked hero-section example with complete code.

Converting a Figma file to code goes wrong in a very specific way: you copy pixel values one element at a time — margin-top: 37px, font-size: 15px, color: #6E56CF — and end up with markup that looks right and is impossible to maintain. The professional workflow is different: you translate the design’s system, then express each screen in that system. Tailwind is ideal for this because it is a design system in utility form. Here’s the whole workflow, then a real conversion.

Step 0: Read the design like an engineer

Before writing any markup, spend ten minutes in Dev Mode (or plain inspect) answering four questions:

  1. What’s the spacing rhythm? Click around — if gaps are 8/16/24/32/48, the file is on an 8-pt grid and maps straight onto Tailwind’s default scale (gap-2/4/6/8/12). If you see 13px and 27px, round them — odd values are almost always designer drift, not intent.
  2. What are the real colors? Check the file’s Variables/Styles panel, not individual fills. A good file has ~6–10 semantic tokens (bg, surface, text-primary, accent…). Those become your theme.
  3. What’s the type scale? List every text style actually used — usually 5–7 (display, h2, h3, body, small, caption). Each becomes a utility combo you reuse, not a per-element font-size.
  4. What repeats? Cards, buttons, badges, nav items. Repetition = a component; you’ll build each once.

Step 1: Tokens → Tailwind theme

Move the file’s variables into Tailwind v4’s CSS-first config so every utility speaks the design’s language:

/* app.css */
@import 'tailwindcss';

@theme {
  /* Figma color variables, verbatim */
  --color-bg: #0b0d12;
  --color-surface: #12151c;
  --color-border: #232733;
  --color-fg: #e8eaf0;
  --color-fg-muted: #9aa1b2;
  --color-accent: #6e56cf;
  --color-accent-soft: #6e56cf1f;

  /* Type + radius from the styles panel */
  --font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif;
  --radius-card: 1rem; /* Figma corner radius 16 */
}

Now bg-surface, text-fg-muted, border-border, rounded-card exist as utilities. When the designer changes a variable, you change one line. This step is what separates a conversion from a transcription.

Step 2: Auto Layout → Flexbox (the mechanical part)

Figma’s Auto Layout is flexbox with different names. The mapping is 1:1:

Figma inspector saysTailwind
Direction: horizontal / verticalflex / flex flex-col
Gap between items: 16gap-4
Padding: 24 / 24 16p-6 / py-6 px-4
Alignment: centeritems-center justify-center
Distribution: space betweenjustify-between
Hug contents(default — don’t set a size)
Fill containerflex-1 or w-full
Fixed width: 384w-96 (only when truly fixed)
Corner radius: 16rounded-2xl
Drop shadow (soft, large)shadow-lg (tune once in @theme)

Read each frame’s Auto Layout panel top-down and type the utilities in the same order. Resist absolute positioning — if the designer used Auto Layout, the layout is flex; if they didn’t, impose the grid they were eyeballing.

Rounding rule: Figma says 37 → use 9 (36px)? No — snap to the nearest scale step (gap-9 exists, but gap-8/32 or gap-10/40 are likelier the intent). Consistency beats fidelity-to-the-pixel; nobody can see 3px, everyone can see inconsistency.

Step 3: A real conversion — hero section

Say Dev Mode shows this for a landing hero:

Frame "Hero" — vertical Auto Layout, gap 24, padding 96/24, items centered
├─ Badge — horiz. layout, gap 8, padding 6/14, radius full,
│         fill accent @ 12%, text 13/medium accent
├─ Heading — Inter 56/64, -2% tracking, weight 700, center, max-w 640
├─ Subtext — Inter 18/28, fg-muted, center, max-w 480
└─ Actions — horiz. layout, gap 12
   ├─ Button "Start free" — padding 12/24, radius 10, fill accent, 15/semibold
   └─ Button "See demo" — same, but border 1px border, fill transparent

The translation, line for line:

<section class="flex flex-col items-center gap-6 px-6 py-24 text-center">
  <!-- Badge: 6/14 padding → py-1.5 px-3.5; 12% accent fill → accent-soft token -->
  <span class="flex items-center gap-2 rounded-full bg-accent-soft px-3.5 py-1.5
               text-[13px] font-medium text-accent">
    ✦ New: v2 is out
  </span>

  <!-- 56/64 with -2% tracking → text-5xl/tight + tracking-tight, capped width -->
  <h1 class="max-w-2xl text-5xl leading-[1.15] font-bold tracking-tight">
    Ship interfaces straight from the design file
  </h1>

  <!-- 18/28 muted → text-lg + relaxed leading, narrower cap -->
  <p class="max-w-md text-lg leading-7 text-fg-muted">
    Convert Figma into clean, responsive Tailwind — without losing the system
    behind the pixels.
  </p>

  <div class="flex flex-wrap items-center justify-center gap-3">
    <a href="#" class="rounded-[10px] bg-accent px-6 py-3 text-[15px] font-semibold
                       text-white transition-colors hover:bg-accent/90">
      Start free
    </a>
    <a href="#" class="rounded-[10px] border border-border px-6 py-3 text-[15px]
                       font-semibold transition-colors hover:bg-surface">
      See demo
    </a>
  </div>
</section>

Notice what happened: every Figma property became a utility in the same order the inspector listed it, odd values snapped to the scale, and the two Figma-specific numbers worth keeping exactly (radius 10, text 15) used arbitrary values rounded-[10px] / text-[15px] — sparingly, deliberately.

Step 4: Responsiveness — the part Figma doesn’t give you

A Figma file is usually 1–2 fixed artboards (1440 and maybe 390). The breakpoints in between are your design decisions. The reliable recipe:

  • Build mobile-first from the 390 frame, then layer md:/lg: utilities to reach the 1440 frame: text-4xl md:text-5xl, flex-col lg:flex-row, px-6 lg:px-8, py-16 lg:py-24.
  • Grids collapse by column count: grid gap-6 sm:grid-cols-2 lg:grid-cols-3 handles 90% of card layouts with no extra thought.
  • When only one artboard exists, derive the mobile version yourself: stack horizontals, halve big paddings, step display text down one size. Show the designer — this is collaboration, not guessing.

Pitfalls that mark a rushed conversion

  • Absolute-positioning the layout because it matched the canvas. It shatters on the first real content change.
  • h-[812px] screens — Figma frames have fixed heights; web pages don’t. Height comes from content; use min-h-screen only for true full-bleed heros.
  • Baked-in text images — retype it; export only real artwork (SVG for icons/logos, compressed raster for photos).
  • Skipping states — Figma shows the resting state. Hover, focus-visible, disabled, and empty states are code’s job: add hover:, focus-visible: rings, and disabled:opacity-50 everywhere interactive.
  • A hundred one-off arbitrary valuesmt-[37px] w-[213px] everywhere means step 0 was skipped. Go back and find the system.

For full worked components — navbar, pricing card, stats grid, and an AI-assisted workflow — continue to Figma to Code: worked examples.