Figma Sync
A Storybook addon to sync Figma designs with components and perform pixel-visual regression testing.
Storybook Addon Figma Sync
A Storybook addon designed to sync Figma design frames directly into Storybook stories. It enables developers to overlay mockups on top of live components with adjustable opacity, auto-resize the Storybook preview iframe to match Figma dimensions, and perform pixel-level visual regression diffing directly in the browser to ensure absolute design fidelity.
Key Features
- Figma Design Integration: Input any Figma Frame URL in the Storybook toolbar to download and display design mockups.
- Figma Panel & Component Discovery: Open the Figma bottom panel to inspect reusable components used by the selected layout. The drawer groups component-set variants, shows usage counts, and links resolvable components back to Figma.
- On-Demand Component Previews: Preview a component as a PNG only when requested. Previews are cached for the current story, can be shown or hidden, and support scroll-to-zoom and drag-to-pan.
- Interactive Visual Overlay: Render the Figma mockup directly over your live component with customizable opacity (0% to 100%) and a toggle switch.
- Automated Component Sizing: Storybook's preview iframe automatically resizes to the exact dimensions of the Figma design frame, ensuring realistic component alignment.
- Pixel-Matching Similarity Analysis: Captures a high-fidelity DOM screenshot of the rendered component using
html-to-imageand compares it pixel-by-pixel with the Figma design usingpixelmatch. - REST API for Automation: Trigger visual audits programmatically via a dev server endpoint, featuring automatic story navigation, render delay buffers, and solid white background compositing for consistent pixelmatch results.
- Advanced Analysis Modal: Switch between three comparison views in the visual audit panel:
- Side-by-Side: Compare the Figma design and live component screenshot side by side.
- Overlay (Interactive): A draggable and zoomable canvas layer where the Figma mockup is overlaid on the component screenshot.
- Diff Only: A visual diff highlighting the pixel mismatch errors in red.
- Single JSON Registry (
registry.json): Persists all sync metadata—such as Story ID, Figma URLs, asset paths, similarity scores, overlay visibility, and opacity percentages—in a single database file, isolating settings per story. - Caching Mechanism: Downloaded Figma design images are stored locally under
.storybook/.storybook-addon-figma-sync/for fast loading and reduced API consumption.
Technology Stack
- React 19: Drives the Storybook addon manager UI, interactive comparison canvas, and modal interfaces.
- Storybook 8+: Integrates with the modern Storybook core channels, globals, parameters, and component registry.
- TypeScript: Ensures type safety across all frontend and backend middleware.
- Vite & Webpack: Exposes Node.js dev server middlewares to serve and cache Figma assets.
- TailwindCSS v4: Integrated for styling storybook components and styling tests.
- Pixelmatch: A pixel-level image comparison library written in JavaScript.
- pngjs: Enables direct PNG decoding, diff output, and encoding inside the Node.js server.
- html-to-image: Converts DOM nodes to high-resolution PNG data URLs on the client.
- tsup: Bundler configured to output targeted ESM modules for the manager, preview, and Node.js preset.
- Vitest: Used as the test runner for unit tests.
Project Architecture
The addon is structured into three main layers: Manager UI (the toolbar and Figma panel), Preview iframe (overlay and screenshot capture), and Node server preset (handles Figma API interaction and image comparisons).
Data Flow & Component Interaction
Getting Started
Prerequisites
- A Figma account and a Figma Personal Access Token (PAT). You can generate one in Figma by going to
Settings > Account > Personal access tokens.
Installation
Install the package as a development dependency using your package manager:
yarn add -D storybook-addon-figma-sync
# or
npm install --save-dev storybook-addon-figma-sync
# or
pnpm add -D storybook-addon-figma-sync
Configuration
1. Register the Addon
Add the addon to your .storybook/main.ts file:
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: [
'@storybook/addon-docs',
{
name: 'storybook-addon-figma-sync',
options: {
envLocation: '../.env', // Path to your environment file containing FIGMA_TOKEN
},
},
],
// Map local cache directory to static URL in Storybook
staticDirs: [{ from: './.storybook-addon-figma-sync', to: '/figma-sync-assets' }],
framework: '@storybook/react-vite',
};
export default config;
2. Set Up Environment Variables
Create a .env file at the root of your project:
FIGMA_TOKEN=your_figma_personal_access_token_here
3. Update Git Ignore
Add the local cache folder to your .gitignore to prevent committing cached Figma designs and screenshot differences:
.storybook/.storybook-addon-figma-sync/
Component Discovery Workflow
After saving a valid Figma frame URL for a story:
- Open Storybook's Figma bottom panel.
- Select Components beside Open in Figma. The first open inspects the layout and lists the Figma components used by its instances.
- Use Search components to filter by component name or variant. Use Refresh only when the Figma layout has changed and you need to fetch the list again.
- Select Show preview to request a PNG preview from Figma. It is cached for the current story; use the mouse wheel to zoom and drag to pan. Select Hide preview to collapse it.
- Select Open in Figma to navigate to the resolved source component.
Some component instances cannot be resolved to a source node by Figma. Those rows show - in the Action column and cannot be previewed or opened from the addon.
REST API for Automated Visual Audits
The addon exposes a built-in REST API endpoint on the Storybook dev server for programmatic triggers (e.g., for CI pipelines, external/agentic scripts, or AI slicing tools).
Endpoint
GET http://localhost:6006/api/figma-sync/screenshot?storyId=<STORY_ID>
Response Example
{
"success": true,
"figmaSrc": "/figma-sync-assets/figma-<storyId>.png",
"screenshotSrc": "/figma-sync-assets/ss-<storyId>.png",
"diffSrc": "/figma-sync-assets/diff-<storyId>.png",
"similarity": 94.25
}
Key Behaviors
- Auto-Navigation: The dev server middleware automatically navigates the active story in the Storybook preview iframe to match the requested
storyId, utilizing a1200msdelay buffer to let the render tree settle before capturing the screenshot. - Transparency Compositing: To resolve false mismatches from alpha channel transparency (e.g., empty backgrounds, transparent PNGs), both the Figma mockup and the captured screenshot are composited onto a solid white background prior to pixelmatch comparison.
- Ignoring Elements: Specific HTML elements can be excluded from screenshots by applying the
data-figma-sync-ignore="true"attribute to them.
Project Structure
storybook-addon-figma-sync/
├── .storybook/ # Local Storybook sandbox configuration
│ ├── .storybook-addon-figma-sync/ # Local cache directory for Figma downloads & diffs (Git ignored)
│ ├── local-preset.ts # Sandbox entry points importing dist assets
│ ├── main.ts # Sandboxed Storybook config
│ └── preview.ts # Sandbox preview globals
├── scripts/ # Automation & prepublish scripts
├── src/ # Source directory
│ ├── components/ # React UI Components
│ │ ├── FigmaSyncTool/ # Toolbar panel settings button & popover
│ │ │ ├── index.tsx
│ │ │ ├── Field.tsx
│ │ │ └── PopoverContent.tsx
│ │ ├── FigmaEmbedPanel/ # Bottom panel, Figma embed, and component discovery drawer
│ │ │ ├── index.tsx
│ │ │ ├── FigmaEmbedFrame.tsx
│ │ │ └── FigmaComponentDiscovery.tsx
│ │ ├── AnalysisModal/ # Side-by-side, overlay, and diff comparison panel
│ │ │ ├── index.tsx
│ │ │ ├── SideBySideView.tsx
│ │ │ ├── OverlayView.tsx
│ │ │ └── DiffView.tsx
│ │ ├── ImageViewer/ # Shared zoomable image viewer and transform context
│ │ │ ├── index.tsx
│ │ │ └── TransformContext.tsx
│ │ └── useOverlayImage.ts # Hooks to verify image availability & resize preview iframe
│ ├── lib/ # Helper libraries
│ │ ├── figma-sync-preview.ts # URL parser and browser screenshot capturing configuration
│ │ ├── figma-sync-server.ts # Node.js file writer, Figma API fetcher, and pixelmatch comparison
│ │ ├── load-image.ts # Async image loader utility
│ │ └── utils.ts # Tailwind merge helper (cn)
│ ├── constants.ts # Channel event names, storybook keys, and default values
│ ├── global.d.ts # Global type definitions
│ ├── index.css # Custom styles
│ ├── index.ts # Addon default exported preview config
│ ├── manager.tsx # Register toolbar buttons in Storybook Manager
│ ├── preset.ts # Webpack and Vite middlewares configuration for Storybook
│ └── preview.ts # Storybook iframe setup, global parameters, and overlay decorator
├── package.json # Package metadata, script pipelines, dependencies
├── tsconfig.json # Strict TypeScript compiler options
└── tsup.config.ts # Bundler configuration separating Manager, Preview, and Node targets
Development Workflow
Local Development
To run the Storybook project locally and develop the addon:
yarn start
This runs the tsup compiler in watch mode (rebuilding code in real-time) and launches the Storybook developer server concurrently.
Build and Package
To build the project for production distribution:
yarn build
This uses tsup to bundle all inputs. It splits files according to their execution targets:
dist/manager.js(Browser Manager UI)dist/preview.js&dist/preview.d.ts(Browser Preview Iframe)dist/preset.js(Node.js Dev Server Middlewares)
Ejecting TypeScript
If you wish to convert this template to standard JavaScript, you can run:
yarn eject-ts
[!WARNING] This is a destructive, irreversible process. We recommend running this before you write any custom addon code.
Coding Standards
This project enforces strict coding quality gates:
- Linting: Rules configured using ESLint. Run checks using
yarn lintor apply fixes withyarn lint:fix. - Formatting: Styles managed using Prettier. Run formatting using
yarn format. - Type Safety: Managed by TypeScript with strict checks. Checked automatically during builds.
- Git Hooks: Integrated with Husky and lint-staged to format and lint changes automatically on git commit.
- Commit Conventions: Conventional commits are enforced using
@commitlint/cliandcommitlint.config.js.
Testing
Backend helpers, asset file structures, and pixel comparisons are tested using Vitest.
To run unit tests:
yarn test
Tests cover:
- base64 PNG data URL decoding.
- Dev-server disk operations (screenshot file writes and deletions).
- Image similarity percentage calculations.
- Error handling (e.g. throwing error outputs when Figma design dimensions mismatch Storybook rendering).
Contributing
Contributions are welcome! Please follow these guidelines:
- Issues: Report bugs or suggest features by creating an issue.
- Branching: Create descriptive branch names (e.g.,
feat/add-fit-modeorfix/opacity-slider). - Pull Requests:
- Ensure all tests pass (
yarn test). - Confirm code is formatted and linted.
- Use conventional commit messages.
- Ensure all tests pass (
Release Management
This repository is configured to use Auto for publishing and release management:
- Make changes and tag your Pull Request with standard labels (e.g.
major,minor,patch). - Once merged, the GitHub Action automatically bumps the version, writes the changelog, and publishes the new bundle to both GitHub and npm.
- To release manually:
yarn release
License
This project is licensed under the MIT License. For full details, see the LICENSE file.