Adding Tailwind output to Design to HTML
How I added a Tailwind mode to my Figma to code plugin: a v4 browser CDN, faithful arbitrary-value utilities, and a flexbox shrink bug that only Tailwind surfaced.
Design to HTML started as a plain CSS exporter: one class per node, a stylesheet in the head. But the most requested format for any Figma to code tool is the same one every time, Tailwind. So I added it. Pick CSS or Tailwind, export, and get a single file where every element carries utility classes and the Tailwind v4 browser build compiles them right in the page.
How the conversion works
The generator already builds a small style object for each node: width, padding, flex direction, colors, the lot. For Tailwind I convert that object into utility classes instead of writing a CSS rule.
Most of it maps to idiomatic utilities. display: flex becomes flex, a vertical auto-layout becomes flex-col, centered content becomes justify-center items-center. Sizes and colors keep their exact values through arbitrary utilities, so a 320 pixel frame is w-[320px] and a fill is bg-[#1a1f26], not a rounded-off scale step. Anything without a clean utility, a gradient, a shadow, a per-side border, falls back to an arbitrary property like [box-shadow:...], which Tailwind accepts and turns into exactly that declaration. The output is faithful to the pixel and still reads like Tailwind, not a pile of inline styles.
The file loads the v4 browser CDN in the head:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
Tailwind's preflight covers the resets I used to write by hand, so the only static CSS left in a Tailwind export is the body centering and the full-width section backgrounds, which have no clean utility form.
The bug Tailwind surfaced
The first real export looked right everywhere except the hero. The image band came out shorter than it should be, its top and bottom margins gone, the photo clipped.
It was not the padding and not the image height, both were correct. The cause was flexbox. The page root exports as a fixed-height flex column. CSS flex items shrink to fit by default, so when the children's total height runs past the root's fixed height, the browser squishes them. Plain CSS mostly got away with it. Tailwind's preflight sets a line height of 1.5, so every line of text runs a little taller, the overflow grows, and the extra shrink collapsed the hero band by over a hundred pixels.
Figma does not work this way. An auto-layout item holds its size and overflows if it has to, it never shrinks to fit. So the fix was to match that: emit flex-shrink: 0 (shrink-0 in Tailwind) on any item that is not set to fill its container. After that the hero band held its height and the top of the page lined up with the CSS export to the pixel. The CSS mode had the same weakness hiding in it, so one change fixed both.
What I checked
The Node harness that stubs the Figma API grew a set of Tailwind assertions: the CDN is in the head, elements carry utilities instead of class rules, the shrink lock is present, and full-width sections still bleed to both edges. I also ran the real export in a browser and measured the hero band before and after the fix, 713 pixels back up to 846, matching the CSS output exactly.
Where it is
CSS and Tailwind now sit side by side behind a small selector in the plugin. It is on the Figma Community and the code is on GitHub, free to use.
Building scalable systems and developer-first tools. Lead Software Engineer at DSRPT.
Frequently asked
-
Yes. A selector chooses plain CSS or Tailwind. The Tailwind output is one self-contained file that loads the Tailwind v4 browser CDN and puts utility classes on every element.
-
It uses arbitrary-value utilities like w-[320px] and bg-[#1a1f26] instead of rounding to the default scale, and arbitrary properties like [box-shadow:...] for gradients, shadows, and per-side borders, so the result matches the design exactly.
-
The root is a fixed-height flex column and CSS flex items shrink by default. Tailwind's preflight sets a taller line height, so text overflowed the fixed height more and the browser squished the hero band. Emitting flex-shrink: 0 on non-fill items, which matches how Figma auto-layout behaves, fixed it in both modes.