Rebuilding a design by hand is mostly repetitive work. You measure padding, guess hex codes, and write the same flex layout you have written many times before. It is not hard, it just takes time.
Vision models are now good enough to read a screenshot and produce a reasonable first draft of that code. I built the Image to Code tool on Toolghar for exactly that, and I use it myself for prototypes and one-off sections. This post covers how to get useful output from it and what I still fix by hand every time.
#What you actually get
You upload an image of a UI (a screenshot, a Figma export, even a rough wireframe) and pick an output format. The tool returns code that tries to reproduce it: structure, text, colors, spacing, and inline SVG for simple icons.
The formats you can choose from:
| Format | Good for |
|---|---|
| HTML + CSS | Static pages, learning, no build step |
| HTML + Tailwind (CDN) | Quick prototypes you can open in a browser |
| HTML + Bootstrap 5 | Admin screens, existing Bootstrap projects |
| React + CSS Modules | React apps without Tailwind |
| React + Tailwind | Most modern React projects |
| Vue 3 | Vue projects (single file component) |
| Next.js + Tailwind | Next.js apps with TypeScript |
Pick the one that matches your project. Converting React output to Vue afterwards is more work than generating it right the first time.
#A real example: a pricing card
Say you screenshot a simple pricing card: plan name, price, a short feature list and a button. With React + Tailwind selected, the output looks roughly like this:
export default function PricingCard() {
return (
<article className="max-w-sm rounded-2xl border border-gray-200 bg-white p-8 shadow-sm">
<h2 className="text-lg font-semibold text-gray-900">Pro</h2>
<p className="mt-4 flex items-baseline gap-1">
<span className="text-4xl font-bold text-gray-900">$29</span>
<span className="text-sm text-gray-500">/month</span>
</p>
<ul className="mt-6 space-y-3 text-sm text-gray-600">
<li>Unlimited projects</li>
<li>Priority support</li>
<li>Custom domain</li>
</ul>
<button
type="button"
className="mt-8 w-full rounded-lg bg-indigo-600 px-4 py-2.5 text-sm font-medium text-white hover:bg-indigo-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2"
>
Get started
</button>
</article>
);
}
That is a decent starting point. It is semantic, the text is real, and the classes are sensible. But notice what it can't know: the price and features are hardcoded, the button does nothing, and indigo-600 is a guess at your brand color. The first thing I usually do is turn it into a component with props:
export default function PricingCard({ name, price, period = "/month", features, onSelect }) {
return (
<article className="max-w-sm rounded-2xl border border-gray-200 bg-white p-8 shadow-sm">
<h2 className="text-lg font-semibold text-gray-900">{name}</h2>
<p className="mt-4 flex items-baseline gap-1">
<span className="text-4xl font-bold text-gray-900">{price}</span>
<span className="text-sm text-gray-500">{period}</span>
</p>
<ul className="mt-6 space-y-3 text-sm text-gray-600">
{features.map((feature) => (
<li key={feature}>{feature}</li>
))}
</ul>
<button
type="button"
onClick={onSelect}
className="mt-8 w-full rounded-lg bg-indigo-600 px-4 py-2.5 text-sm font-medium text-white hover:bg-indigo-700"
>
Get started
</button>
</article>
);
}
Five minutes of work, and now it is something you can actually use in a page.
#My workflow, step by step
#1. Get a clean image
Export from Figma or your design tool at 2x, or take a normal screenshot at full resolution. Don't photograph your screen with a phone. If the image is huge, the Image Resizer is fine for bringing it down without losing legibility.
#2. Crop to one component
This makes the biggest difference. If you want the navbar, upload only the navbar. A full landing page in one image gives the model too much to get wrong, and you end up with one giant component that's hard to clean up. I build pages section by section and assemble them myself.
#3. Generate, then read the code
Read it before you paste it into your project. Things I check first:
- Is the structure semantic (
nav,header,section,button) or a pile ofdivs? - Is the copy right? OCR on small text can swap letters.
- Are there made up asset paths for images or logos?
- Does it use anything your project doesn't have (a font, a Tailwind plugin, an icon library)?
#4. Make it production code
Replace hardcoded content with props or data, wire up real handlers, map colors to your design tokens, and test on mobile. If you only need plain markup without a framework, Image to HTML is the simpler option.
TIP
[!TIP] Once one card or section is cleaned up, reuse it. Generating five similar cards separately gives you five slightly different versions of the same component.
#Common problems and fixes
| Problem | Why it happens | Fix |
|---|---|---|
| Spacing is a bit off everywhere | Padding is estimated from pixels | Snap to your spacing scale (for example p-6, gap-4) |
| Colors are close but not exact | Sampled from a compressed image | Replace with your theme tokens |
| Wrong or generic font | Fonts can't be reliably detected from an image | Set your real font in the config or CSS |
| Layout breaks on mobile | Screenshot only showed desktop | Add or adjust sm: and md: rules, test in dev tools |
| Tailwind classes have no effect | Your project uses a different Tailwind version or config | Check the classes against your setup (Tailwind docs) |
| Icons look rough | Complex icons redrawn as inline SVG | Swap in your icon library |
| Hover or open states missing | A static image doesn't show them | Add the states and logic yourself |
The tool is asked to include accessible markup (labels, alt text, focus styles), but I still check it. Alt text written from a screenshot is often generic, and focus order across a whole page is something you have to test with a keyboard.
WARNING
[!WARNING] Don't paste generated code into production without reading it. It can look right in the browser and still have hardcoded text, missing labels or asset paths that don't exist.
#Where it works and where it doesn't
It works well for landing page sections, pricing cards, navbars, footers, forms, simple dashboards and tables. These follow common patterns, and the model has seen plenty of them.
It is weaker on dense data UIs, heavy animation, anything that depends on state you can't see in a still image, and strict brand systems where every value must match a token. For those, I still use it for the rough layout, but I expect to rewrite more.
It is also useful for learning. If you are new to Tailwind or React, converting a layout you like and reading the output shows you how someone would actually build it.
#Quick recap
- Crop to one component and use a sharp 2x export, not a phone photo.
- Pick the output format that matches your stack before generating.
- Expect a solid first draft. Spacing, colors, fonts and behavior need your pass.
- Turn hardcoded content into props and check accessibility and breakpoints yourself.
- The Image to Code tool runs on free daily credits, with optional one-time credit packs if you need more. More utilities are in Developer Tools.