Design
Overview
Handoff between design and engineering breaks at scale. Here's the component naming, token structure, and review process we use to keep it seamless.
Sana Yildiz
Designer: "It's all in Figma, just build it" Engineer: "The spacing is inconsistent, the components don't match, and where are the hover states?"
Sound familiar? The gap between design and code is where products go to die. After 50+ projects, we've built a workflow that bridges that gap completely.
Figma to code workflow diagram
The most important shift: Treat your Figma file as code. Every color, space, and font should map directly to your codebase's design tokens.
Figma Variable → CSS Custom Property → Tailwind Config
─────────────────────────────────────────────────────
color/primary/500 → --color-primary-500 → colors.primary.500
space/400 → --spacing-4 → spacing.4
font/size/heading/1 → --font-size-h1 → fontSize.h1
In Figma: Create color variables with semantic names:
color/primarycolor/background/basecolor/text/primarycolor/border/defaultIn Code:
/* globals.css */
:root {
--color-primary: #3b82f6;
--color-background-base: #ffffff;
--color-text-primary: #111827;
--color-border-default: #e5e7eb;
}
.dark {
--color-primary: #60a5fa;
--color-background-base: #111827;
--color-text-primary: #f9fafb;
--color-border-default: #374151;
}
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
primary: 'var(--color-primary)',
background: {
base: 'var(--color-background-base)',
},
text: {
primary: 'var(--color-text-primary)',
},
border: {
default: 'var(--color-border-default)',
}
}
}
}
}
Color token mapping visualization
In Figma: Create spacing variables:
space/100 = 4pxspace/200 = 8pxspace/300 = 12pxspace/400 = 16pxspace/500 = 24pxspace/600 = 32pxspace/800 = 48pxspace/1000 = 64pxIn Code:
// tailwind.config.js
module.exports = {
theme: {
extend: {
spacing: {
100: '4px',
200: '8px',
300: '12px',
400: '16px',
500: '24px',
600: '32px',
800: '48px',
1000: '64px',
}
}
}
}
In Figma: Create text styles:
Heading 1: 32px/40px/700Heading 2: 24px/32px/600Body Large: 18px/28px/400Body Base: 16px/24px/400Caption: 14px/20px/400In Code:
// tailwind.config.js
module.exports = {
theme: {
extend: {
fontSize: {
'h1': ['32px', { lineHeight: '40px', fontWeight: '700' }],
'h2': ['24px', { lineHeight: '32px', fontWeight: '600' }],
'body-lg': ['18px', { lineHeight: '28px', fontWeight: '400' }],
'body': ['16px', { lineHeight: '24px', fontWeight: '400' }],
'caption': ['14px', { lineHeight: '20px', fontWeight: '400' }],
}
}
}
}
For every component in Figma, create a spec:
# Button Component
## Variants
- primary (blue background, white text)
- secondary (gray background, gray text)
- outline (transparent, blue border)
## Sizes
- sm: 32px height, 12px horizontal padding
- md: 40px height, 16px horizontal padding
- lg: 48px height, 24px horizontal padding
## States
- default
- hover (darken background by 10%)
- active (scale 0.98)
- disabled (50% opacity)
## Figma frame name: Button / [Variant] / [Size]
Example: Button / Primary / MD
// components/ui/Button.tsx
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'
const buttonVariants = cva(
'inline-flex items-center justify-center rounded-md font-medium transition-all focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50',
{
variants: {
variant: {
primary: 'bg-blue-600 text-white hover:bg-blue-700 active:scale-98',
secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',
outline: 'border-2 border-blue-600 text-blue-600 hover:bg-blue-50',
},
size: {
sm: 'h-8 px-3 text-sm',
md: 'h-10 px-4 text-base',
lg: 'h-12 px-6 text-lg',
},
},
defaultVariants: {
variant: 'primary',
size: 'md',
},
}
)
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {}
export function Button({ className, variant, size, ...props }: ButtonProps) {
return (
<button
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
)
}
Component variant mapping
Export design tokens automatically:
// tokens.json (exported from Figma)
{
"color": {
"primary": { "value": "#3b82f6" },
"background": { "base": { "value": "#ffffff" } }
},
"spacing": {
"400": { "value": "16px" }
}
}
Then transform to Tailwind config:
// scripts/transform-tokens.js
const tokens = require('./tokens.json')
module.exports = {
theme: {
extend: {
colors: Object.entries(tokens.color).reduce((acc, [key, value]) => {
acc[key] = value.value
return acc
}, {})
}
}
}
Sync Figma components with Storybook:
// Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react'
import { Button } from './Button'
const meta: Meta<typeof Button> = {
title: 'UI/Button',
component: Button,
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/.../Button',
},
},
}
export const Primary: StoryObj = {
args: {
variant: 'primary',
children: 'Click me',
},
}
Designer checks:
Engineer checks:
Pair review of a single component:
// app/style-guide/page.tsx
export default function StyleGuide() {
return (
<div>
<section>
<h2>Colors</h2>
<div className="grid grid-cols-4 gap-4">
{Object.entries(colors).map(([name, value]) => (
<div key={name} className="space-y-2">
<div className="h-20 rounded" style={{ backgroundColor: value }} />
<p>{name}</p>
<p className="text-sm text-gray-500">{value}</p>
</div>
))}
</div>
</section>
<section>
<h2>Buttons</h2>
<div className="space-x-4">
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
</div>
</section>
</div>
)
}
Living style guide screenshot
Before:
After:
The secret isn't a tool or plugin — it's shared language and process. When designers think in components and engineers think in design tokens, handoff becomes collaboration. And that's when great products get built.
Written by
Sana Yildiz
Keep Reading
Stop fighting Tailwind's utility classes. Learn how we compose tokens, variants, and component abstractions into a coherent design system.
Most scroll animations feel cheap. Here's the exact easing, timing, and trigger logic we use to make motion feel premium and intentional.
Let's work together