Skip to main content
BlogWeb Dev

My Figma to Next.js Component Workflow

How I translate Figma designs into production-ready Next.js components without losing fidelity or wasting time on guesswork.

Matthews Wong

Software Engineer

June 20259 min read
My Figma to Next.js Component Workflow

Photo by Unsplash

There's a painful gap between a polished Figma design and a working React component. Pixel values that don't map to Tailwind defaults. Color names in the design system that bear no relation to the CSS variable names in the codebase. After iterating on this workflow across several projects — including this portfolio — I've landed on a process that keeps design fidelity high and translation time low.

Before You Write a Line of Code: Auditing the Design

The single biggest time-saver is spending 30 minutes auditing the Figma file before touching code. What I'm looking for: inconsistencies in the design token usage, auto-layout usage (Figma's auto-layout maps directly to CSS flexbox), and component hierarchy (are variants used consistently?). A design that uses auto-layout throughout and a proper local variables/styles setup translates almost mechanically.

Figma Dev Mode: What It Actually Gives You

Figma's Dev Mode (the inspector panel with the less-than greater-than toggle) is useful but requires interpretation. It gives you exact pixel values, auto-layout direction and gap, corner radius, opacity, and color in various formats. What it doesn't give you is semantic meaning — it won't tell you that a color is brand-500 in your design system, or that a spacing value maps to gap-6 in Tailwind.

Establishing the Tailwind Config as the Design Token Bridge

The Figma variables panel and the Tailwind config need to use the same names for the same values. I set up the Tailwind config before writing components, extending the theme to match Figma variable names exactly: if Figma has color/brand/500, the Tailwind key is brand-500. This creates a one-to-one mapping: when a designer says 'use brand-500', I know exactly which Tailwind class to write.

┌─────────────┐    Inspect     ┌──────────────────────┐
│   FIGMA     │ ─────────────► │  Design Tokens        │
│  (Design)   │   Dev Mode     │  colors, spacing,     │
└─────────────┘                │  typography, radius   │
                               └──────────┬───────────┘
                                          │ tailwind.config.ts
                                          ▼
┌─────────────────────────────────────────────────────┐
│              COMPONENT MAPPING                      │
│                                                     │
│  Figma Frame/Group  →  React Component              │
│  Figma Auto-layout  →  flex / grid classes          │
│  Figma Variant      →  TypeScript props union       │
│  Figma Component    →  Storybook story              │
└──────────────────────────┬──────────────────────────┘
                           │ build
                           ▼
                    Next.js Page
                 (server components)

Install the Figma plugin Tokens Studio for Figma (formerly Style Dictionary) to export design tokens directly as a JSON file, then use Style Dictionary to generate your Tailwind config extension automatically. For projects with more than 50 unique tokens, this eliminates an entire category of manual sync errors.

Component Translation: From Figma Frame to TypeScript Props

Every Figma component becomes a TypeScript interface. Figma variants map to TypeScript union types. Figma boolean properties map to optional boolean props. The challenge is deciding what to expose as a prop versus what to hardcode. My rule: anything the designer explicitly made a variant or a configurable style override should be a prop.

Handling Responsive Behavior and Figma Breakpoints

Figma designs are typically for a single viewport width — usually desktop (1440px) or mobile (375px). Responsive behavior is implied, not always explicitly designed. When translating to Next.js, I use Tailwind's responsive prefixes (sm:, md:, lg:) to interpolate between the two designed states.

// tailwind.config.ts — mirror Figma token names exactly
import type { Config } from "tailwindcss"

const config: Config = {
  theme: {
    extend: {
      colors: {
        brand: {
          50:  "#eff6ff",
          500: "#3b82f6",  // match Figma "brand/500"
          900: "#1e3a5f",
        },
      },
      spacing: {
        18: "4.5rem",  // custom Figma spacing token
      },
      borderRadius: {
        "2xl": "1rem",  // Figma corner radius
      },
    },
  },
}
export default config

// components/ui/Button.tsx — typed props from Figma variants
type ButtonVariant = "primary" | "secondary" | "ghost"
type ButtonSize = "sm" | "md" | "lg"

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: ButtonVariant
  size?: ButtonSize
  loading?: boolean
}

const variantClasses: Record<ButtonVariant, string> = {
  primary: "bg-brand-500 text-white hover:bg-brand-600",
  secondary: "bg-transparent border border-brand-500 text-brand-500",
  ghost: "bg-transparent text-brand-500 hover:bg-brand-50",
}

const sizeClasses: Record<ButtonSize, string> = {
  sm: "px-3 py-1.5 text-sm",
  md: "px-4 py-2 text-base",
  lg: "px-6 py-3 text-lg",
}

export function Button({
  variant = "primary",
  size = "md",
  loading,
  children,
  className,
  ...props
}: ButtonProps) {
  return (
    <button
      className={`rounded-2xl font-medium transition-colors ${variantClasses[variant]} ${sizeClasses[size]} ${className ?? ""}`}
      disabled={loading}
      {...props}
    >
      {loading ? <span className="animate-spin">⏳</span> : children}
    </button>
  )
}

Storybook as the Design–Dev Handoff Artifact

Every component I build from Figma gets a Storybook story alongside it. The story covers each variant exactly as it appears in Figma, plus edge cases the design doesn't show — empty states, long strings, loading states, error states. Storybook serves as a living bridge between the design and the implementation.

Spending hours matching a 2px spacing difference visible only at 200% zoom is almost always the wrong tradeoff. Ship at 95% fidelity quickly, collect user feedback, then refine. Agree on an explicit tolerance level with your designer before the component review — it saves arguments and late-night pixel-hunting sessions.

Handling Icons: Lucide, Custom SVGs, and the Icon Component Pattern

Icon management is a detail that causes disproportionate friction. I use Lucide React as the default icon library — it's tree-shakeable, consistent in style, and covers the vast majority of UI needs. For custom icons from the design (the brand logo, product-specific icons), I export them from Figma as SVGs, optimize them with SVGO, and wrap them in a simple React component that accepts a size prop and className.

When the Design Doesn't Exist Yet

Sometimes I'm building features where the designer is still working on the Figma file, or there's no designer at all. In that case, I start with the component API first — define the TypeScript interface for the props, stub the component with placeholder content, and write the Storybook story. The component design emerges from the props, not the other way around.

Sources & Further Reading

FAQ

Frequently Asked Questions

Short answers to what readers ask most about this topic.

Why should I audit the Figma file before writing any code?

Spending 30 minutes auditing the Figma file upfront is the single biggest time-saver in the workflow. It lets you spot inconsistencies in design token usage, check that auto-layout is used consistently (which maps directly to CSS flexbox), and confirm component variants are applied uniformly. A design with proper auto-layout and local variable setup translates almost mechanically into code.

How do you keep Figma design tokens in sync with the Tailwind config?

The Figma variables panel and the Tailwind config must use the same names for the same values. The approach is to extend the Tailwind theme so keys match Figma variable names exactly — if Figma has color/brand/500, the Tailwind key is brand-500. For projects with more than 50 unique tokens, the Tokens Studio for Figma plugin can export design tokens as a JSON file, and Style Dictionary can then generate the Tailwind config extension automatically, eliminating an entire category of manual sync errors.

How do Figma variants and boolean properties translate into TypeScript?

Each Figma component becomes a TypeScript interface. Figma variants map to TypeScript union types, and Figma boolean properties map to optional boolean props. The guiding rule is: anything the designer explicitly made a variant or a configurable style override should be exposed as a prop; everything else can be hardcoded.

What role does Storybook play in the Figma-to-Next.js handoff?

Every component built from a Figma design gets a Storybook story alongside it. The story covers each variant exactly as it appears in Figma, plus edge cases the design does not show — empty states, long strings, loading states, and error states. Storybook acts as a living bridge between the design file and the implementation, making it the shared reference for both designers and developers.

How should icons from the Figma design be handled in Next.js?

Lucide React is the default icon library — it is tree-shakeable, stylistically consistent, and covers the vast majority of UI needs. For custom brand or product-specific icons from the Figma file, the workflow is to export them as SVGs, optimize them with SVGO, and wrap them in a simple React component that accepts a size prop and a className prop.