MinhVo

Minh Vo

rss feed

Slaying code & making it lit fr fr 🔥 tagline

Hey there 👋 I'm an AI Engineer with 7 years of experience building scalable web and mobile applications. Currently at Neurond AI (May 2025 — present), architecting an Enterprise AI Assistant Platform with multi-tenant RAG on pgvector, multi-provider LLM orchestration, and Azure-native infrastructure. Previously spent 5+ years at SNAPTEC (Sep 2019 — Apr 2025), leading SaaS themes, admin dashboards, and e-commerce platforms — earned the Hero of the Year award in 2021. I specialize in TypeScript, React, Next.js, and AI-Native engineering with Claude Code and Cursor.bio

Back to blogs

Figma for Developers: Design-to-Code Workflow

Bridge design and code: Figma inspect, design tokens, auto-layout, and developer handoff.

FigmaDesignFrontendUI/UX

By MinhVo

Introduction

Figma has become the industry standard for UI/UX design, and understanding how to work with Figma as a developer is no longer optional—it is essential. The design-to-code workflow bridges the gap between designers and developers, ensuring that what gets built matches the design vision while being technically feasible. In this comprehensive guide, we will explore Figma's developer-focused features, design token extraction, auto-layout to CSS mapping, component documentation, and automated workflows that transform designs into production-ready code.

The traditional handoff process—where designers throw designs over the wall and developers interpret them—is fraught with miscommunication, inconsistency, and wasted effort. Modern design-to-code workflows eliminate this friction by establishing shared languages (design tokens), automated extraction tools, and component-based architectures that map design components directly to code components. Figma's API and plugin ecosystem make this automation accessible to any team.

Figma Design Interface

Understanding Figma for Developers: Core Concepts

Figma's developer experience revolves around several key features. The Inspect panel provides detailed CSS, iOS, and Android properties for any selected element, including dimensions, colors, typography, spacing, and effects. This panel is the primary tool for translating designs into code, but it is just the starting point.

Auto-layout is Figma's equivalent of CSS Flexbox. It defines how elements are arranged within a frame: direction (horizontal or vertical), spacing between items, padding, and alignment. Understanding auto-layout is crucial because it maps directly to CSS Flexbox properties. A horizontal auto-layout with 16px gap and center alignment translates to display: flex; flex-direction: row; gap: 16px; align-items: center;.

Components in Figma map directly to React components. A Figma component with variants (e.g., Button with Primary/Secondary variants and Small/Medium/Large sizes) corresponds to a React component with props. Understanding this mapping enables developers to build components that exactly match the design system.

Design tokens are the shared language between design and code. They are named values for colors, typography, spacing, border-radius, shadows, and other design properties. Instead of hardcoding #3B82F6 in code, you use color.primary.500. Figma variables (introduced in 2023) natively support design tokens, enabling bidirectional sync between Figma and code.

The Figma REST API provides programmatic access to design files, enabling automated extraction of design tokens, component metadata, and asset exports. This API powers custom tools that generate code, documentation, and style guides from Figma designs.

Figma plugins extend Figma's functionality with custom tools. Plugins like "Design Tokens", "Content Reel", and "Auto Layout" enhance the design-to-code workflow. Developers can also build custom plugins for team-specific needs.

Design Tokens

Architecture and Design Patterns

Design Token Architecture

Design tokens form the foundation of a design system. They are organized in a hierarchy: global tokens (raw values like color scales), alias tokens (semantic names like color.primary), and component tokens (component-specific values like button.background). This hierarchy enables theme switching, dark mode, and brand customization by changing only the alias layer.

Component Mapping Pattern

Figma components map directly to code components. The mapping includes: component name to component name, variants to props, auto-layout to Flexbox, and text styles to typography tokens. This 1:1 mapping ensures consistency between design and code.

Figma API Integration

The Figma REST API enables automated workflows: extracting design tokens from Figma variables, exporting assets as optimized images, generating component documentation, and validating that code matches design specifications.

Style Dictionary Integration

Style Dictionary by Amazon transforms design tokens into platform-specific formats: CSS custom properties, TypeScript constants, iOS Swift constants, and Android XML resources. This ensures tokens are available in every platform and language used by the team.

Automated Design QA

Automated tools compare rendered components against Figma designs pixel-by-pixel. Tools like Storybook's visual regression testing and Percy detect visual differences between design and implementation, catching discrepancies before they reach production.

Step-by-Step Implementation

Let us build a complete design-to-code workflow that extracts design tokens from Figma, generates TypeScript constants, and creates React components that match the design system.

First, set up the Figma API client:

// lib/figma-client.ts
interface FigmaConfig {
  accessToken: string;
  fileKey: string;
}
 
class FigmaClient {
  private baseUrl = 'https://api.figma.com/v1';
 
  constructor(private config: FigmaConfig) {}
 
  private async fetch<T>(endpoint: string): Promise<T> {
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      headers: { 'X-Figma-Token': this.config.accessToken },
    });
    if (!response.ok) throw new Error(`Figma API error: ${response.status}`);
    return response.json();
  }
 
  async getFile(): Promise<FigmaFile> {
    return this.fetch(`/files/${this.config.fileKey}`);
  }
 
  async getFileStyles(): Promise<FigmaStyle[]> {
    const file = await this.getFile();
    return file.styles ? Object.values(file.styles) : [];
  }
 
  async getFileVariables(): Promise<FigmaVariable[]> {
    return this.fetch(`/files/${this.config.fileKey}/variables/local`);
  }
 
  async exportImages(nodeIds: string[], format: 'svg' | 'png' | 'jpg' = 'svg'): Promise<Record<string, string>> {
    const ids = nodeIds.join(',');
    const result = await this.fetch<{ images: Record<string, string> }>(
      `/images/${this.config.fileKey}?ids=${ids}&format=${format}`
    );
    return result.images;
  }
}

Extract design tokens from Figma variables:

// scripts/extract-tokens.ts
interface DesignToken {
  name: string;
  value: string | number;
  type: 'color' | 'typography' | 'spacing' | 'borderRadius' | 'shadow' | 'opacity';
  description?: string;
}
 
async function extractTokens(client: FigmaClient): Promise<DesignToken[]> {
  const tokens: DesignToken[] = [];
  const variables = await client.getFileVariables();
 
  for (const variable of variables.meta.variables) {
    const token: DesignToken = {
      name: variable.name,
      value: '',
      type: mapVariableType(variable.resolvedType),
    };
 
    // Get the default mode value
    const defaultMode = Object.keys(variable.valuesByMode)[0];
    const value = variable.valuesByMode[defaultMode];
 
    if (typeof value === 'object' && 'r' in value) {
      // Color value
      token.value = colorToHex(value as RGBA);
    } else if (typeof value === 'number') {
      token.value = value;
    } else if (typeof value === 'string') {
      token.value = value;
    }
 
    tokens.push(token);
  }
 
  return tokens;
}
 
function colorToHex(color: { r: number; g: number; b: number; a?: number }): string {
  const r = Math.round(color.r * 255);
  const g = Math.round(color.g * 255);
  const b = Math.round(color.b * 255);
  const a = color.a !== undefined && color.a !== 1
    ? Math.round(color.a * 255).toString(16).padStart(2, '0')
    : '';
  return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}${a}`;
}
 
function mapVariableType(type: string): DesignToken['type'] {
  switch (type) {
    case 'COLOR': return 'color';
    case 'FLOAT': return 'spacing';
    case 'STRING': return 'typography';
    default: return 'color';
  }
}

Generate TypeScript constants from tokens:

// scripts/generate-tokens.ts
import fs from 'fs';
 
function generateTypeScript(tokens: DesignToken[]): string {
  const grouped = groupTokensByCategory(tokens);
 
  let output = `// Auto-generated from Figma - Do not edit manually
// Generated at: ${new Date().toISOString()}
 
`;
 
  for (const [category, categoryTokens] of Object.entries(grouped)) {
    output += `export const ${camelCase(category)} = {\n`;
    for (const token of categoryTokens) {
      const name = token.name.split('/').pop()!;
      const value = typeof token.value === 'string' ? `'${token.value}'` : token.value;
      output += `  ${camelCase(name)}: ${value},\n`;
    }
    output += `} as const;\n\n`;
  }
 
  // Generate CSS custom properties
  output += `export const cssCustomProperties = \`\n:root {\n`;
  for (const token of tokens) {
    const name = `--${token.name.toLowerCase().replace(/\//g, '-')}`;
    output += `  ${name}: ${token.value};\n`;
  }
  output += `}\n\`;\n`;
 
  return output;
}
 
function groupTokensByCategory(tokens: DesignToken[]): Record<string, DesignToken[]> {
  const groups: Record<string, DesignToken[]> = {};
  for (const token of tokens) {
    const category = token.name.split('/')[0];
    if (!groups[category]) groups[category] = [];
    groups[category].push(token);
  }
  return groups;
}
 
function camelCase(str: string): string {
  return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase())
    .replace(/[^a-zA-Z0-9]/g, '');
}
 
// Run extraction and generation
async function main() {
  const client = new FigmaClient({
    accessToken: process.env.FIGMA_ACCESS_TOKEN!,
    fileKey: process.env.FIGMA_FILE_KEY!,
  });
 
  const tokens = await extractTokens(client);
  const typescript = generateTypeScript(tokens);
 
  fs.writeFileSync('src/tokens/index.ts', typescript);
  console.log(`Generated ${tokens.length} design tokens`);
}
 
main().catch(console.error);

Create React components that map to Figma components:

// components/Button.tsx - Maps to Figma Button component with variants
import { cva, type VariantProps } from 'class-variance-authority';
 
const buttonVariants = cva(
  'inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
  {
    variants: {
      variant: {
        primary: 'bg-primary-500 text-white hover:bg-primary-600 focus-visible:ring-primary-500',
        secondary: 'bg-secondary-100 text-secondary-900 hover:bg-secondary-200 focus-visible:ring-secondary-500',
        outline: 'border border-primary-500 text-primary-500 hover:bg-primary-50 focus-visible:ring-primary-500',
        ghost: 'text-primary-500 hover:bg-primary-50 focus-visible:ring-primary-500',
      },
      size: {
        small: 'h-8 px-3 text-sm',
        medium: 'h-10 px-4 text-sm',
        large: 'h-12 px-6 text-base',
      },
    },
    defaultVariants: {
      variant: 'primary',
      size: 'medium',
    },
  }
);
 
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>,
  VariantProps<typeof buttonVariants> {
  loading?: boolean;
  icon?: React.ReactNode;
}
 
export function Button({ variant, size, loading, icon, children, ...props }: ButtonProps) {
  return (
    <button className={buttonVariants({ variant, size })} disabled={loading} {...props}>
      {loading && <Spinner className="mr-2 h-4 w-4" />}
      {!loading && icon && <span className="mr-2">{icon}</span>}
      {children}
    </button>
  );
}

Design System Components

Real-World Use Cases and Case Studies

Use Case 1: Shopify's Polaris Design System

Shopify's Polaris design system uses Figma as the single source of truth for all UI components. Design tokens are extracted from Figma variables and transformed into CSS custom properties, TypeScript constants, and Swift/Kotlin constants. Every component in code has a 1:1 mapping to a Figma component, and automated visual regression tests verify that implementations match designs.

Use Case 2: Airbnb's Design Language System

Airbnb's DLS uses Figma components with complex variants that map directly to React components. Their custom Figma plugin extracts component metadata, generates TypeScript types for props, and creates Storybook stories with all variant combinations. This automation reduced the design-to-code handoff time from days to minutes.

Use Case 3: GitHub's Primer Design System

GitHub's Primer design system uses Figma variables for design tokens, which are synced to CSS custom properties and TypeScript constants using a custom tool. The sync process runs automatically when designers update tokens in Figma, and a CI pipeline verifies that the generated code matches the current Figma state.

Use Case 4: Microsoft's Fluent UI

Microsoft's Fluent UI uses Figma as the design source for components across web, Windows, iOS, and Android. Design tokens are extracted from Figma and transformed into platform-specific formats using Style Dictionary. This ensures visual consistency across all platforms while allowing each platform to use native UI components.

Best Practices for Production

  1. Establish a single source of truth: Use Figma as the single source of truth for design tokens and components. Do not hardcode design values in code—always derive them from Figma tokens. This ensures that design changes propagate automatically to code.

  2. Use Figma variables for design tokens: Figma variables (introduced in 2023) provide native support for design tokens with modes (light/dark), scoping (color/spacing/typography), and aliases. Migrate from Figma styles to variables for better token management.

  3. Map Figma components to code components 1:1: Every Figma component should have a corresponding code component with the same name, same variants, and same default values. This 1:1 mapping makes it trivial to translate designs to code.

  4. Automate token extraction: Set up a CI pipeline that extracts tokens from Figma on every design change and generates code artifacts. Use the Figma REST API or Figma plugin API for extraction.

  5. Use auto-layout as CSS Flexbox: When implementing Figma designs, translate auto-layout directly to CSS Flexbox. Horizontal auto-layout becomes flex-direction: row, vertical becomes flex-column. Gap, padding, and alignment translate directly.

  6. Export assets as SVG: Use Figma's export feature to export icons and illustrations as SVG. SVG scales perfectly, has small file sizes, and can be styled with CSS. Use SVGR to convert SVGs into React components.

  7. Document components in Figma: Add descriptions, usage guidelines, and do/don't examples to Figma components. This documentation travels with the component and helps developers understand how to use it correctly.

  8. Implement visual regression testing: Use tools like Chromatic, Percy, or Storybook's built-in visual testing to compare rendered components against Figma designs. This catches visual discrepancies before they reach production.

Common Pitfalls and Solutions

PitfallImpactSolution
Hardcoding design values in codeInconsistency between design and code; manual updates neededUse design tokens extracted from Figma
Ignoring auto-layout semanticsLayout doesn't match design on different screen sizesMap auto-layout directly to CSS Flexbox
Not syncing tokens automaticallyDesign and code diverge over timeSet up automated token extraction pipeline
Missing component variantsComponents don't support all design statesExtract all variants from Figma and implement as props
Pixel-perfect obsessionWasted effort on imperceptible differencesFocus on functional accuracy; use visual regression testing
Not using Figma components properlyDesign inconsistency; duplicate workEstablish component usage guidelines for designers

Performance Optimization

The design-to-code workflow can be optimized by automating repetitive tasks and caching extracted data.

// Cached Figma file processor
class FigmaFileProcessor {
  private cache: Map<string, { data: any; timestamp: number }> = new Map();
  private cacheTtlMs = 5 * 60 * 1000; // 5 minutes
 
  constructor(private client: FigmaClient) {}
 
  async getFileWithCache(): Promise<FigmaFile> {
    const cached = this.cache.get('file');
    if (cached && Date.now() - cached.timestamp < this.cacheTtlMs) {
      return cached.data;
    }
 
    const file = await this.client.getFile();
    this.cache.set('file', { data: file, timestamp: Date.now() });
    return file;
  }
 
  async extractComponents(): Promise<FigmaComponent[]> {
    const file = await this.getFileWithCache();
    const components: FigmaComponent[] = [];
 
    const traverse = (node: FigmaNode) => {
      if (node.type === 'COMPONENT') {
        components.push({
          id: node.id,
          name: node.name,
          variants: this.extractVariants(node),
          autoLayout: this.extractAutoLayout(node),
        });
      }
      if ('children' in node) {
        node.children.forEach(traverse);
      }
    };
 
    traverse(file.document);
    return components;
  }
 
  private extractVariants(node: FigmaNode): Record<string, string[]> {
    const variants: Record<string, string[]> = {};
    // Extract variant properties from component set
    return variants;
  }
 
  private extractAutoLayout(node: FigmaNode): AutoLayout | null {
    if (!('layoutMode' in node) || !node.layoutMode) return null;
    return {
      mode: node.layoutMode,
      spacing: node.itemSpacing || 0,
      padding: {
        top: node.paddingTop || 0,
        right: node.paddingRight || 0,
        bottom: node.paddingBottom || 0,
        left: node.paddingLeft || 0,
      },
      alignment: node.primaryAxisAlignItems || 'MIN',
    };
  }
}

Comparison with Alternatives

FeatureFigmaSketchAdobe XDPenpot
Web-BasedYesNo (macOS only)No (desktop)Yes
Real-Time CollaborationYesVia pluginsLimitedYes
Developer HandoffBuilt-in InspectVia ZeplinBuilt-inBuilt-in
Design TokensVariablesVia pluginsLimitedCSS variables
API AccessREST APIFile-basedLimitedREST API
Component VariantsYesVia symbolsYesYes
Auto-LayoutYesVia pluginsYesYes
Plugin EcosystemVery largeLargeMediumGrowing
PricingFree tier availablePaidFree tierFree (open source)

Advanced Patterns

Figma Plugin for Code Generation

Build a custom Figma plugin that generates React component code directly from selected Figma components.

// figma-plugin/code.ts
figma.showUI(__html__, { width: 400, height: 600 });
 
figma.ui.onmessage = async (msg) => {
  if (msg.type === 'generate-code') {
    const selection = figma.currentPage.selection;
    if (selection.length === 0) {
      figma.ui.postMessage({ type: 'error', message: 'No selection' });
      return;
    }
 
    const component = selection[0];
    const code = generateReactComponent(component);
 
    figma.ui.postMessage({
      type: 'generated-code',
      code,
      componentName: component.name,
    });
  }
};
 
function generateReactComponent(node: SceneNode): string {
  const componentName = pascalCase(node.name);
  const props = extractProps(node);
  const styles = extractStyles(node);
  const children = generateChildren(node);
 
  return `
interface ${componentName}Props {
${props.map(p => `  ${p.name}: ${p.type};`).join('\n')}
}
 
export function ${componentName}({ ${props.map(p => p.name).join(', ')} }: ${componentName}Props) {
  return (
${children}
  );
}
`;
}

Testing Strategies

Test the design-to-code workflow by verifying that extracted tokens match Figma values and that generated components match designs.

describe('Design Token Extraction', () => {
  it('should extract color tokens from Figma', async () => {
    const mockClient = createMockFigmaClient({
      variables: [
        { name: 'color/primary/500', resolvedType: 'COLOR', valuesByMode: { default: { r: 0.23, g: 0.51, b: 0.96, a: 1 } } },
      ],
    });
 
    const tokens = await extractTokens(mockClient);
 
    expect(tokens).toHaveLength(1);
    expect(tokens[0].name).toBe('color/primary/500');
    expect(tokens[0].value).toBe('#3b82f6');
    expect(tokens[0].type).toBe('color');
  });
 
  it('should generate valid TypeScript from tokens', () => {
    const tokens: DesignToken[] = [
      { name: 'color/primary', value: '#3b82f6', type: 'color' },
      { name: 'spacing/small', value: 8, type: 'spacing' },
    ];
 
    const output = generateTypeScript(tokens);
 
    expect(output).toContain("primary: '#3b82f6'");
    expect(output).toContain('small: 8');
  });
});

Future Outlook

The design-to-code workflow is evolving toward full automation. AI-powered tools are beginning to generate code directly from design screenshots, while Figma's Dev Mode provides an enhanced developer experience with better code generation, component documentation, and design system integration.

The adoption of design tokens as an industry standard (W3C Design Tokens Community Group) is creating interoperability between tools. In the future, design tokens will be a first-class concept in CSS, making the design-to-code bridge even more seamless. The convergence of design tools, code editors, and browser devtools is creating a unified workflow where designs and code are always in sync.

Conclusion

Figma has transformed the design-to-code workflow from a manual, error-prone process into an automated, systematic practice. By leveraging Figma's developer features—Inspect, auto-layout, variables, and API—developers can extract design tokens, generate code, and maintain design systems with minimal manual effort.

Key takeaways: (1) Use Figma variables as the source of truth for design tokens; (2) Map Figma auto-layout directly to CSS Flexbox; (3) Establish 1:1 mapping between Figma components and code components; (4) Automate token extraction with the Figma API; (5) Implement visual regression testing to catch design-code discrepancies; (6) Document components in Figma for developer reference.

The investment in a robust design-to-code workflow pays dividends in consistency, velocity, and quality. When designers and developers share a common language through design tokens and component libraries, the result is software that looks exactly as designed and is built exactly as specified. Start by extracting your design tokens from Figma, and progressively build the automation that keeps design and code in perfect sync.