TL;DR
Going from a Figma design to production React code is a multi-step process. Study the design first, map values to design tokens, plan your component tree, build small pieces, then assemble the full page. This workflow saves hours of refactoring and keeps your codebase clean with Tailwind CSS and reusable UI components.
The Handoff Problem Everyone Knows
We've all been there. A designer sends you a gorgeous Figma file. You open it up and your first thought is "okay cool, but what about the mobile version?" Or "what happens when this text is really long?" Or "where's the empty state?"
The gap between a Figma mockup and working frontend code isn't just about turning colors into hex codes. It's about all the stuff that a static picture can't show you. Loading states, error handling, edge cases with long content, responsive behavior on different screen sizes, accessibility, and keyboard navigation.
After doing this hundreds of times, building React components from Figma designs for web applications of all sizes, I've got a system that works. Let me walk you through it step by step.
This isn't some theoretical framework from a blog post I read somewhere. This is the actual workflow I use every single day when building production frontend code. It's been refined through real projects, real deadlines, and real feedback from designers who care deeply about their work being translated faithfully into the browser. Whether you're building with Next.js, plain React, or any other frontend framework, the principles are the same.
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ STEP 1 │ │ STEP 2 │ │ STEP 3 │ │ STEP 4 │ │ STEP 5 │ │ │ │ │ │ │ │ │ │ │ │ Study the │───▶│ Map to │───▶│ Plan the │───▶│ Build small │───▶│ Responsive │ │ design │ │ tokens │ │ components │ │ first │ │ pass │ │ │ │ │ │ │ │ │ │ │ │ 15-20 min │ │ 30 min │ │ 20 min │ │ Hours │ │ 1-2 hours │ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
Step 1: Study the Design Before You Code
Before I write a single line of code, I spend 15 to 20 minutes just looking at the design in Figma Dev Mode. Not glancing at it. Actually studying it. This is the most important step and the one most frontend developers skip.
I know what you're thinking. "I don't have time to just stare at a design for 20 minutes." But here's the thing: every minute you spend studying the design saves you five minutes of refactoring later. I've seen developers jump straight into coding and end up rewriting their entire component structure three times because they didn't notice a pattern in the design that should have been a shared component. That's hours wasted, not minutes saved.
What I Look For
- Spacing patterns: Is everything on an 8px grid? 4px? Is the spacing consistent throughout?
- Color usage: Which colors match our existing design tokens? Are there any new ones?
- Typography: What font sizes and weights are being used? Do they match our type scale?
- Component boundaries: Where does one UI component end and another begin?
- Repeated patterns: What shows up more than once? That's definitely a reusable component.
- Interactive states: Are hover, focus, active, and disabled states designed?
- Layout structure: Is it a grid? Flexbox? How does the layout hierarchy work?
- Iconography: What icon set is being used? Do we already have these icons?
Asking the Right Questions
While studying the design, I write down every question that pops into my head. Things designers sometimes forget to spec out but engineers need to know. This is especially important in frontend development where the gap between a static mockup and a dynamic web application is huge.
Questions I Always Ask
- What happens when the list is empty? Is there an empty state design?
- Does this text truncate with an ellipsis or wrap to multiple lines?
- What does the loading state look like? Skeleton screens or spinners?
- What happens on error? Is there an error state for this form?
- How does this layout respond on tablet and mobile screen sizes?
- Are there any animations or transitions between states?
- What about keyboard navigation and screen reader accessibility?
- What's the maximum and minimum width of this container?
- Does this component need to support right-to-left languages?
Pro Tip
Batch all your questions and send them to the designer at once. Way better than pinging them every 10 minutes throughout the day. Designers appreciate focused, thoughtful feedback. I usually compile my questions into a single message with numbered items and reference screenshots. This shows you've actually studied their work carefully, and they're much more likely to give you thorough answers in return.
Step 2: Map Design Values to Tokens
This is where most frontend developers mess up. They see a color in the Figma design and hard-code the hex value directly into their CSS or Tailwind classes. Then six months later when the brand colors change, they're updating values in 47 files across the codebase.
Instead, I map every value in the design to an existing design token first. Design tokens are the shared language between your design system in Figma and your code in React. They're the bridge that makes the handoff smooth and maintainable. When both designers and developers speak the same language of tokens, you eliminate an entire category of miscommunication.
Why Tokens Matter So Much
Design tokens are the secret to building maintainable web applications. When you use tokens like bg-primary instead of bg-[#6366F1] in your Tailwind CSS classes, you get dark mode support for free. You get theme switching for free. You get consistent colors across your entire React component library. And when the design team decides to change the primary color from indigo to teal, you update one CSS variable and the entire application follows. That's the kind of maintainability that separates amateur projects from professional ones.
Token Categories to Check
- Colors: Primary, secondary, destructive, muted, accent, background, foreground
- Typography: Font family, sizes (xs through 4xl), weights, line heights
- Spacing: Padding, margin, and gap values on the 4px grid
- Border radius: sm, md, lg, xl, full
- Shadows: sm, md, lg, xl for elevation levels
- Transitions: Duration and easing for animations
Handling Values That Don't Map
Sometimes a design includes values that don't match any existing token. Maybe the designer used a 14px font size that sits between your text-xs (12px) and text-sm (14px). Or a color that's close to but not exactly your primary color. This is where communication becomes critical. I always bring these discrepancies up with the designer rather than making assumptions. Nine times out of ten, it was unintentional and they're happy to snap it to the nearest token value. That one time out of ten, it's a deliberate choice and we should add a new token to our design system.
Step 3: Plan the Component Tree
Before touching any code, I sketch out what React components I need. I literally write this out as notes or comments. It saves hours of refactoring later because I know exactly what to build and what already exists in our design system.
This planning step is where experience really pays off. A junior developer might look at a settings page and see one big page to build. A senior developer sees five reusable components that can be assembled in different configurations. The senior developer's code is more flexible, more testable, and takes about the same amount of time to write. The difference is entirely in the planning phase.
The Component Decision Framework
For every piece of UI in the design, I ask three questions to decide what to do. This framework has saved me from building dozens of unnecessary components over the years. It keeps your codebase lean and your design system focused.
┌──────────────────────────┐
│ Does this UI pattern │
│ exist in our system? │
└─────────┬────────────────┘
│
┌─────────┴─────────┐
│ │
YES NO
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────────┐
│ Use the existing │ │ Will it be reused │
│ component as-is │ │ elsewhere? │
└─────────────────┘ └────────┬────────────┘
│
┌─────────┴─────────┐
│ │
YES NO
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ Build a reusable │ │ Build it inline │
│ component with │ │ on the page. │
│ props and docs. │ │ Extract later if │
│ Add to Storybook.│ │ needed. │
└──────────────────┘ └──────────────────┘The Component Naming Convention
Naming matters more than you think. I follow a simple convention: generic components get generic names (Card, Button, Input), while composed or feature-specific components get descriptive names (SettingsCard, UserProfileForm, NotificationToggle). This makes it immediately clear which components are part of the base design system and which are built for specific features. It also helps with code search. When someone asks "where's the settings card?" they can find it instantly.
Step 4: Build Small First, Then Compose
I always start with the smallest pieces and work my way up. Build the reusable UI components first. The page layout comes last. This is the core of good React component architecture and it makes your codebase so much easier to maintain.
There's a reason this approach works so well. When you build bottom-up, each piece gets your full attention. You handle edge cases properly. You write clean TypeScript interfaces. You make sure the component looks good in isolation. Then when you compose them together on the page, everything just works because each piece was built correctly. Compare this to the top-down approach where you build the entire page at once and then try to extract components later. That extraction almost never happens cleanly because the pieces are tangled together.
Building a Reusable Component
Here's what one of those small, reusable components looks like. Notice how it uses TypeScript for type safety and Tailwind CSS for styling. Every prop has a clear purpose and nothing is overcomplicated.
Why Small Components Win
Small React components are easier to test, easier to reuse, and easier to understand. When each component does one thing well, composing them into complex pages becomes straightforward. This is the foundation of every good design system and component library. It's also much easier to review in pull requests. When a PR changes a small, focused component, the reviewer can understand the change in seconds. When a PR changes a 500-line page component, the review takes forever and bugs slip through.
Composing the Page
Once all the small pieces are built and tested, assembling the page is almost anticlimactic. It's just importing components and arranging them. The page file reads like a table of contents for the UI. Each section is clearly named, and the overall structure is easy to scan.
Step 5: Make It Work on Every Screen Size
Most Figma designs only show the desktop version. But real people use phones, tablets, and everything in between. Responsive design is not optional in modern web development. I do a separate pass just for responsive behavior after the desktop version looks good.
I intentionally save the responsive pass for after the desktop version is solid. Trying to build desktop and mobile at the same time splits your focus and leads to messy compromises. Get the layout right on desktop first, then adjust for smaller screens. Tailwind CSS makes this easy with its mobile-first responsive prefixes.
Responsive Patterns in Tailwind CSS
Mobile-First Approach
Tailwind CSS uses a mobile-first responsive system. Your base styles are for mobile, and you add breakpoint prefixes like sm:, md:, and lg: to override for larger screens. This approach forces you to think about the smallest screen first, which usually results in cleaner, simpler markup. The mobile version strips away the nice-to-haves and focuses on the core content, which is actually a better starting point for any layout.
Breakpoints I Use Most
- sm (640px): Large phones in landscape, small tablets
- md (768px): Tablets and small laptops
- lg (1024px): Standard laptops and desktops
- xl (1280px): Large screens and wide monitors
Testing Responsive Behavior
Don't just resize your browser window and call it done. Test on actual devices when you can. iOS Safari and Android Chrome have quirks that desktop browser dev tools don't simulate. Touch targets need to be at least 44px. Scroll behavior differs between mobile browsers. The viewport height on mobile is tricky because of the address bar. These are the kinds of things you only catch by testing on real hardware.
Step 6: Handle the States Nobody Designs
This is my bonus step that turns good frontend work into great frontend work. Every feature has states beyond the "happy path" that the Figma design shows. Building these states is what separates a polished web application from a prototype.
UI States Every Component Needs:
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ LOADING │ │ SUCCESS │ │ ERROR │
│ │ │ │ │ │
│ Skeleton or │ │ Show data │ │ Error msg │
│ spinner │ │ normally │ │ + retry │
└──────┬───────┘ └──────────────┘ └──────┬───────┘
│ │
│ ┌──────────────┐ │
└────────▶│ EMPTY │◀─────────────┘
│ │ (after retry
│ Empty state │ still fails)
│ illustration│
│ + CTA │
└──────────────┘Common Mistakes to Avoid
I've seen these mistakes hundreds of times in code reviews. Here's what to watch out for when turning Figma designs into React components for your web applications.
Hard-Coding Pixel Values
If you're writing margin-top: 23px, something is wrong. The designer probably meant 24px, which maps to mt-6 in Tailwind CSS. Always round to the nearest value in your spacing system. Just ask the designer if you're unsure.
Building Components That Already Exist
Before making a new React component, always check your design system library first. If something close exists, add a variant to it instead of creating a whole new component. This keeps your component library lean and consistent.
Only Building the Happy Path
The Figma design shows perfect data. But real web applications need empty states, loading skeletons, error messages, and handling for super long text that breaks your layout. Push back on designs that skip these. Users will hit every edge case you can imagine.
Forgetting Dark Mode
If your Next.js app has dark mode, every component needs to work in both themes. Using semantic tokens like bg-card instead of bg-white in Tailwind CSS handles this automatically. It's one of the biggest benefits of using design tokens.
Pixel-Perfect Over Good Engineering
The goal isn't to match every pixel. It's to capture the design intent while building something that lasts. A component that's 2 pixels off but uses proper tokens, handles all states, and is accessible is better than a pixel-perfect component with hard-coded values.
Tools I Actually Use Every Day
There are tons of tools out there for design-to-code workflows. Here are the ones I actually use in my daily work as a design engineer building with React and Next.js.
Design Inspection
- Figma Dev Mode: For grabbing exact spacing, colors, and font values from designs
- Figma Tokens plugin: Keeps design tokens in sync between Figma and your codebase
Development and Testing
- Storybook: Building and testing React components in isolation before they hit the page
- Chromatic: Automated visual regression testing that catches UI bugs in pull requests
- Tailwind IntelliSense: VS Code extension that autocompletes Tailwind CSS classes
Quality Checks
- axe DevTools: Browser extension for quick accessibility audits
- Responsively: Preview your UI on multiple screen sizes at once
- Vercel Preview Deploys: Share running code with designers for feedback before merge
Working Well With Designers
The workflow isn't just tools and steps. It's fundamentally about collaboration. The relationship between you and your designer makes or breaks the quality of the final product. Here are the habits that make the biggest difference.
Show Running Code Early
Don't wait until you're done to show the designer. Deploy a preview build on Vercel and share the link. They'll spot things in a running web app that they never would have noticed in a static design review. Real browsers reveal real issues. Interactive states feel different when you can actually click them. Animations need to be experienced, not imagined.
Explain Technical Constraints
When you have to change something for technical reasons, always explain why and suggest an alternative that achieves the same design intent. Don't just say "we can't do that." Say "we can't do that because of X, but here's an approach that gets us 95% there." Designers respect engineers who understand design intent, even when the implementation needs to differ.
Share Your Component Library
Give designers access to your Storybook. Let them see what UI components already exist so they can design with real constraints. This prevents them from designing things that would require building entirely new components when a variant of an existing one would work just as well.
Celebrate Good Specs
When a build matches the design perfectly on the first try, tell the designer. It means their spec was excellent. Positive feedback encourages them to keep providing detailed, well-thought-out designs. This small habit improves the quality of every future handoff you receive.
Handling Edge Cases Like a Pro
Edge cases are where good frontend development separates itself from great frontend development. Here are the edge cases I check for on every single feature I build.
Content Edge Cases
- What if the title is 200 characters long?
- What if there are zero items in the list?
- What if there are 10,000 items?
- What if the user's name contains special characters or emojis?
State Edge Cases
- Loading state when data is being fetched
- Error state when the API call fails
- Empty state when there's no data yet
- Stale state when data might be outdated
Device Edge Cases
- Very small screens (320px width)
- Very large screens (4K monitors)
- Touch vs. mouse vs. keyboard interaction
- Slow network connections
The Complete Workflow Summary
Your Design-to-Code Checklist
- Spend 15-20 minutes studying the Figma design before writing any code
- Map every design value to an existing token or Tailwind CSS class first
- Plan your React component tree on paper or in comments
- Build the smallest reusable UI components first, page layout last
- Do a separate responsive design pass for mobile, tablet, and desktop
- Build loading, error, and empty states for every data-driven component
- Use semantic design tokens so dark mode and theming just work
- Check all edge cases: empty, loading, error, long content, and small screens
- Talk to your designer early and often, and show running code on preview deploys
- Test accessibility with keyboard navigation and a screen reader
This workflow might seem like a lot of steps, but it actually saves time. When you plan before you code, you avoid the painful refactoring that happens when you dive in too fast. Every hour spent studying a design and planning components saves three hours of rewriting code later.
The best frontend developers I know all have a system like this. It doesn't have to be exactly my system. But having any structured approach to turning Figma designs into React components will make your code cleaner, your designs more accurate, and your relationship with designers way better. Whether you're working with Next.js, Tailwind CSS, or any other tools in the frontend ecosystem, the principles remain the same: study first, plan second, build third. Your future self will thank you for it.