Figma Integration: From Embeds to a Real Design Model

Connecting Figma components to their coded counterparts, with stable references that survive file changes.

Figma Integration: From Embeds to a Real Design Model

Knapsack is a B2B enterprise SaaS platform for design systems, software that helps product teams build, document, and publish their design foundations at scale.


What we were trying to solve

Knapsack already had a way to bring Figma into docs: iframe embeds of frames, prototypes, and components. It worked, but created its own problems. Iframes were heavy, behaved poorly inside structured docs, and had no awareness of what they embedded. A frame was just a URL, with no concept of what component it represented or where it sat in the file.

Screenshots were the other workaround, and had the same problem: docs looked right until the design changed, with no signal when it drifted.

The before state. Iframe embeds and static screenshots as the primary ways to get Figma into documentation, with no stable references to the underlying design content.

Beyond documentation, Knapsack components and Figma components existed in isolation. A button in code had no relationship to the button in Figma. We needed Figma to be a structured data source inside Knapsack, not just a place to grab embeds from.

Where I fit in

As Director of Product Design, I owned product definition, UX, and cross-functional alignment end to end: the data model, the selector experience, and how Figma nodes integrated with Knapsack's block system.

I worked closely with engineering, defining the node model and API contract early so the team could build against a stable spec, and driving alignment on what v1 needed versus what we left for later. I built the foundational UI myself, then worked with engineers on the API layer.

How I approached it

I started by mapping what teams needed from Figma inside docs: connecting files, browsing to the right node, and referencing it in a way that stayed stable as designs evolved.

Three constraints shaped the design: Figma's hierarchy (file, page, frame, component, variant) had to be respected, not flattened, or the integration would be fragile; large files meant we needed a clear model of what to sync and when; and everything had to work within Knapsack's existing block-based model.

From there I defined a unified node model (stable id, name, type, URL, breadcrumb path, thumbnail) and designed a selector that made it navigable without authors managing URLs manually. I validated tree-based browsing with internal users, testing it against search-only and link-pasting for finding a node in a large file.

The calls that mattered

A browseable selector over paste-a-link

A link approach would have shipped faster, but kept the burden on authors: know the link, keep it updated, re-paste when it broke. The selector inverted that. Authors pick a node, and Knapsack holds the stable reference: one selection experience serving multiple block types.

Snapshot model over live sync

Live sync would mean designs could change underneath documentation at any time, with no signal or control. The snapshot model fixed that: content stays stable within a branch until an author deliberately triggers a sync. Nothing moves until someone decides it should, the same intentionality the branch workflow gave authors elsewhere.

Components and variants as first-class node types

Treating components and variants as distinct types, rather than flattening everything to "frame," was harder to build but essential. "Show this frame" and "document this component" are different jobs, and building that distinction into the node model from the start meant we could support real component documentation, not just visual embedding.

Linking Figma components to Knapsack components

Once a Figma component was linked to its Knapsack counterpart, its properties and variants mapped automatically to the coded component's props and API. Teams got a structured data view right on the component page: design spec and coded spec side by side, instead of a spreadsheet someone had to update by hand.

What actually shipped

Design Source management and sync

When a Figma file is connected, Knapsack pulls the content via the Figma API and stores it in its own system. Authors work from that snapshot within their branch, then trigger a manual sync when ready to incorporate updates.

Connecting a Figma file

Figma-to-Knapsack component linking

Once linked, the integration automatically maps Figma component properties and variants to the coded component's props and API, giving teams an always-current view of how the design spec relates to the implementation, directly on the component page.

Connecting a Figma component
Component API Comparison
Component API Comparison
Component API Missing in Code
Component API Missing in Code

Teams that had been working around iframe limitations now had design spec and coded spec side by side, for the first time in one view.

Documenting Figma Assets in Knapsack

Two new block types shipped alongside a design source selector for browsing connected files down to component and variant: a tiles block for displaying a grid of frames or components, and a component block for documenting a specific component with its variants and usage. The existing embed block remained for teams who wanted full iframe embeds.

Selecting Figma assets for use in documentation

What I'd do differently

I'd push for earlier alignment on the data model with engineering. Some of the most productive conversations happened later than they should have. Defining the node model as a shared artifact upfront would have compressed the back-and-forth during implementation.

This reinforced something I carry into every integration feature: model the domain the way the tool does. The moment we tried to simplify Figma's hierarchy too early, the design got harder to reason about.

The snapshot model has also become a default for me on any platform work with an external source of truth: intentional sync keeps documentation honest and prevents the silent drift of treating a live feed as a feature rather than a liability.

Next WorkCloud Authoring: A Branch Workflow Content Teams Can Actually Use  →