figma-to-react

star 213

Use when the user wants to extract Figma designs into production-ready React or Next.js components with TypeScript, Tailwind CSS, and pixel-perfect accuracy.

majiayu000 By majiayu000 schedule Updated 6/5/2026

name: figma-to-react description: Use when the user wants to extract Figma designs into production-ready React or Next.js components with TypeScript, Tailwind CSS, and pixel-perfect accuracy.

Figma to React - Production-Ready Component Generator

๐ŸŽฏ Purpose

Extract complete, lossless design information from Figma and generate production-ready React/Next.js components with TypeScript and Tailwind CSS.


๐Ÿšจ CRITICAL RULES - Read First!

Rule 1: NEVER Truncate Code

Use 100% of Figma MCP output. Every className, every property matters.

// โœ… CORRECT: Keep ALL className from Figma MCP
<div className="absolute font-source-serif h-[108px] leading-[1.8] left-[100px] not-italic text-[20px] text-[rgba(29,38,45,0.8)] text-justify top-[210px] w-[1096px] whitespace-pre-wrap">

// โŒ WRONG: Removing any className
<div className="absolute left-[100px] top-[210px] font-source-serif text-[20px]">

Rule 2: Flatten absolute contents Structures

๐Ÿ”ฅ CRITICAL: Figma MCP returns nested absolute contents containers. display: contents makes the parent "disappear" - children are positioned relative to the nearest positioned ancestor (root)!

Key Insight: Children's positions are ALREADY absolute - DO NOT add parent's top/left!

// โŒ WRONG: Figma MCP output (has redundant parent wrapper)
<div className="absolute contents left-0 top-[41px]">
  <p className="absolute left-[100px] top-[41px]">TITLE</p>
  <div className="absolute left-0 top-[100px]">Line</div>
</div>

// โœ… CORRECT: Just remove the parent wrapper, keep children's positions AS-IS
<>
  <p className="absolute left-[100px] top-[41px]">TITLE</p>
  <div className="absolute left-0 top-[100px] w-[1920px] h-[1px] bg-[#C5CBCE] opacity-30" />
</>

Position Handling Rules:

Parent Type Child Position Action
absolute contents Child has own top/left Keep child position AS-IS, just remove parent
absolute (no contents) Child has relative top/left Calculate: parent + child
relative Child has top/left Calculate: parent + child

๐Ÿ”ฅ The Golden Rule:

If parent has "contents" class โ†’ Child positions are already absolute โ†’ Keep AS-IS
If parent has NO "contents" class โ†’ Child positions are relative โ†’ Add parent + child

Reference: Verified correct positions (from production HTML):

  • Header text: top-[41px] (not 82px)
  • Header line: top-[100px] (not 141px)
  • Footer line: top-[980px]
  • Page number: top-[1004px]

Rule 3: Extract Dimensions from Metadata

NEVER hardcode dimensions!

// 1. Get metadata first
const metadata = await mcp__figma__get_metadata({
  fileKey: 'xxx',
  nodeId: '11:1420'
})

// 2. Extract from XML
// <frame width="1920" height="1080">
const pageWidth = 1920
const pageHeight = 1080

// 3. Use extracted values
<div className="w-[1920px] h-[1080px]">

Rule 4: Font Loading & Name Mapping

๐Ÿ”ฅ CRITICAL: Use Google Fonts CDN directly, NOT next/font/google!

next/font/google generates CSS variables and self-hosts fonts, but the font rendering may differ from reference HTML that uses Google Fonts CDN directly. This causes:

  • Different character widths (text wrapping issues)
  • Different optical size handling for variable fonts

4.1 Font Loading (layout.tsx)

// โŒ WRONG: Using next/font/google
import { Source_Serif_4, Kaisei_Tokumin } from 'next/font/google'
const sourceSerif = Source_Serif_4({ subsets: ['latin'], variable: '--font-source-serif' })
// This may render fonts differently than Google Fonts CDN!

// โœ… CORRECT: Use Google Fonts CDN directly in layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <head>
        <link rel="preconnect" href="https://fonts.googleapis.com" />
        <link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
        <link
          href="https://fonts.googleapis.com/css2?family=Source+Serif+4:ital,opsz,wght@0,8..60,200..900;1,8..60,200..900&family=Kaisei+Tokumin:wght@400;500;700;800&display=swap"
          rel="stylesheet"
        />
      </head>
      <body>{children}</body>
    </html>
  )
}

Key: Include opsz (optical size) axis for Source Serif 4 - this affects character widths!

4.2 Font CSS (globals.css)

@layer utilities {
  /* Use direct font-family names, NOT CSS variables */
  .font-source-serif {
    font-family: 'Source Serif 4', serif;
  }
  .font-kaisei {
    font-family: 'Kaisei Tokumin', serif;
  }
}

4.3 Font Name Mapping

// Figma MCP returns:
font-['Kaisei_Tokumin:ExtraBold',sans-serif]
font-['Source_Serif_Pro:SemiBold',sans-serif]

// โœ… Convert to Tailwind classes:
font-kaisei font-extrabold
font-source-serif font-semibold

// Font name corrections (Google Fonts 2024):
'Source Serif Pro' โ†’ 'Source Serif 4'
'Source Sans Pro' โ†’ 'Source Sans 3'

4.4 Font Weight Mismatch Warning

โš ๏ธ Figma's font weight names may NOT match CSS font-weights!

Figma renders fonts differently than browsers. What Figma calls "Bold" might visually appear lighter than CSS font-weight: 700.

Figma Weight Name Expected CSS May Actually Need
Regular 400 400
Medium 500 500
Bold 700 500 or 600 (test visually!)
ExtraBold 800 700 (test visually!)

Solution: Always compare with Figma screenshot. If text looks too bold, try one weight lighter:

  • font-bold (700) โ†’ try font-medium (500)
  • font-extrabold (800) โ†’ try font-bold (700)

Rule 5: Critical CSS

Must add to globals.css:

body {
  overflow-x: auto; /* Allow horizontal scroll */
}

.page-container {
  min-width: max-content;  /* Prevent compression */
  display: inline-block;   /* Keep layout intact */
}

Rule 6: Replace Simple Images with CSS

Optimize line images:

// โŒ Before: Image-based line
<div className="absolute h-0 left-0 top-[100px] w-[1920px]">
  <div className="absolute inset-[-1px_0_0_0]">
    <img src={imgLine} />
  </div>
</div>

// โœ… After: CSS-based line
<div className="absolute left-0 top-[141px] w-[1920px] h-[1px] bg-[#C5CBCE] opacity-30" />

Rule 7: Inline SVG Assets

// โŒ Before: External image
<img src={imgVector} />

// โœ… After: Inline SVG
<svg viewBox="0 0 35 34" fill="none">
  <path d="M17.5 0L0 34..." fill="#1d262d"/>
</svg>

Rule 7.5: Remove Fixed Heights from Text Blocks

๐Ÿ”ฅ CRITICAL: Figma MCP outputs fixed heights for text blocks, but this causes line-wrapping issues!

Font metrics differ between Figma's rendering and browser rendering (even with the same font family). Fixed heights can cause:

  • Text overflow or clipping
  • Different line counts than expected
  • Layout breaks when font rendering differs slightly
// โŒ WRONG: Figma MCP output with fixed height
<p className="absolute h-[72px] leading-[1.8] left-[100px] text-[20px] top-[570px] w-[1096px]">
  Long text that might wrap differently in browser...
</p>

// โœ… CORRECT: Remove h-[Xpx], let text flow naturally
<div className="absolute leading-[1.8] left-[100px] text-[20px] top-[570px] w-[1096px]">
  <p className="mb-0">Long text that might wrap differently in browser...</p>
</div>

When to keep fixed heights:

  • Container elements (cards, boxes) - keep dimensions
  • Table rows with single-line content - keep h-[34px]
  • Images and icons - keep dimensions

When to remove fixed heights:

  • Multi-line text paragraphs - ALWAYS remove h-[Xpx]
  • Text blocks with text-justify - especially important
  • Any text that could wrap differently

Pattern: Use <div> wrapper with <p className="mb-0">:

// This matches reference HTML structure and ensures proper text flow
<div className="absolute font-source-serif leading-[1.8] left-[100px] text-[20px] top-[570px] w-[1096px]">
  <p className="mb-0">Text content here...</p>
</div>

Extended Reference

Detailed material starting at ### **Rule 8: Table Pattern Detection & Conversion** has been moved to reference/extended.md to keep this skill concise. Load that reference when the task requires the moved examples, command catalogs, checklists, platform details, or implementation templates.

Install via CLI
npx skills add https://github.com/majiayu000/spellbook --skill figma-to-react
Repository Details
star Stars 213
call_split Forks 21
navigation Branch main
article Path SKILL.md
More from Creator