@figit/dom-to-figma

中文文档
0.2.4发布于 2026/08/22MITTypeScriptES Module构建来源已验证近 30 天下载 3.1万

Convert any DOM tree to a Figma clipboard payload, in the browser.

原始使用文档
文档目录12 节
  1. Install
  2. What it does
  3. Layout
  4. Multi-frame canvas
  5. Result shape
  6. Trace mode
  7. Customizing loaders
  8. Fonts
  9. Images
  10. Classification
  11. Runtime requirements
  12. Disclaimer

@figit/dom-to-figma

Convert any DOM tree to a Figma clipboard payload, in the browser.

import { createFigmaConverter } from "@figit/dom-to-figma";

const figma = createFigmaConverter();

const result = await figma.convert({
  element: document.getElementById("design"),
  width: 1280,
  height: 800,
  name: "Hero",
});

await navigator.clipboard.write([result.toClipboardItem()]);

Paste in Figma. Done.

Install

pnpm add @figit/dom-to-figma

What it does

Walks a real DOM tree, reads computed styles, and produces what Figma reads on paste. Text becomes editable text; images, vectors, gradients, shadows, borders, and form placeholders all carry over.

Used in production by Sleek to copy designs straight from the browser into Figma.

Layout

By default the converter infers native Figma auto-layout: flex containers, plain block flow, wrapping rows, and grids become real stacks (stackMode, spacing, padding, hug/fill/stretch sizing), and absolutely positioned children ride along as absolute-positioned layers. Inference is per-container and verified against the browser's measured geometry — any container it can't reproduce exactly falls back to absolute positioning, so the result is never worse than a fixed-position paste.

const figma = createFigmaConverter(); // layout: "auto" (default)

Pass layout: "absolute" to disable inference and position every frame absolutely (the pre-1.0 behavior):

const figma = createFigmaConverter({ layout: "absolute" });

Multi-frame canvas

Pass frames instead of a single element to copy several DOM trees onto one Figma canvas:

const result = await figma.convert({
  frames: [
    { element: a, width: 800, height: 600, x: 0,   y: 0, name: "Hero" },
    { element: b, width: 800, height: 600, x: 900, y: 0, name: "Pricing" },
  ],
  canvasName: "Landing",
});

await navigator.clipboard.write([result.toClipboardItem()]);

Result shape

type ConvertResult = {
  document: FigmaClipboard;          // raw node-change document
  bytes: Uint8Array;                 // encoded .fig-style binary
  base64: string;                    // base64 of bytes
  toClipboardItem(): ClipboardItem;  // ready for navigator.clipboard.write
  toClipboardHtml(): string;         // raw HTML envelope Figma reads on paste
};

Trace mode

Pass trace: true to also get a map from every emitted Figma node back to the DOM element it came from. It is off by default, adds no cost when disabled, and never changes the payload bytes — it exists for tooling (visual diffing, debugging) rather than production copies.

const figma = createFigmaConverter({ trace: true });
const result = await figma.convert({ element, width: 1280, height: 800 });

for (const entry of result.trace.entries) {
  // entry.guid    → the emitted node's Figma GUID
  // entry.domPath → ":scope > div:nth-child(2) > p:nth-child(1)"
  // entry.rect    → source rect (getBoundingClientRect) at convert time
  // entry.kind / entry.tag / entry.text
}

domPath resolves the source element with root.querySelector(domPath) (the root element is :scope). Text nodes carry their owner element's path plus a ::text[i] suffix, and each wrapped line segment of one text node shares that path. result.trace is undefined unless the converter was created with { trace: true }.

Customizing loaders

The converter takes three optional hooks:

const figma = createFigmaConverter({
  fontLoader,   // (props) => Promise<FontFile>
  imageLoader,  // (req) => Promise<ImageFile>
  classify,     // (element, defaultKind) => ElementKind
});

Repeated convert() calls on the same converter reuse cached fonts and images. Call figma.clearCache() to drop them.

Fonts

Default: createFontsourceLoader() pulls fonts from fontsource via jsDelivr's CDN. Covers all Google Fonts plus other open-source families. No API key required.

import { createFontsourceLoader } from "@figit/dom-to-figma";

const figma = createFigmaConverter({
  fontLoader: createFontsourceLoader({ subset: "latin-ext" }),
});

For non-fontsource fonts, write your own loader:

import type { FontLoader } from "@figit/dom-to-figma";

const myFontLoader: FontLoader = async ({ family, weight, italic }) => {
  const url = await myFontCDN(family, weight, italic);
  const response = await fetch(url);
  return { bytes: await response.arrayBuffer() };
};

Images

Default: createDirectImageLoader() does a direct fetch(src). Cross-origin images without CORS need a custom loader, typically a proxy chain:

import type { ImageLoader } from "@figit/dom-to-figma";

const myImageLoader: ImageLoader = async ({ src }) => {
  const url = `https://my-proxy.example/?url=${encodeURIComponent(src)}`;
  const response = await fetch(url);
  const blob = await response.blob();
  return {
    bytes: await blob.arrayBuffer(),
    mimeType: blob.type,
  };
};

The package re-encodes WebP/AVIF/etc. to PNG internally, so the loader only needs to return raw bytes and a mime type.

Classification

classify lets you override how DOM elements map to Figma node kinds. The default classifier returns text, image, vector, frame, group, form-with-placeholder, or skip:

import type { Classify } from "@figit/dom-to-figma";

const classify: Classify = (element, defaultKind) => {
  if (element.dataset.role === "text-wrapper") {
    return "text";
  }
  return defaultKind;
};

Runtime requirements

Runs in any modern browser. Depends on window.getComputedStyle, Blob, ClipboardItem, document.createElement, crypto.subtle.digest, Image, and <canvas>.

Disclaimer

Not affiliated with or endorsed by Figma.

版本与发布记录

@figit/dom-to-figma 共发布 8 个版本,首次发布于 2026/05/19;过去 12 个月发布了 8 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.2.4latest2026/08/222 个月前
0.2.32026/08/222 个月前
0.2.22026/08/063 个月前
0.2.12026/07/233 个月前
0.2.02026/07/223 个月前
0.1.02026/07/114 个月前

关于 @figit/dom-to-figma 的常见问题

@figit/dom-to-figma 是什么?

Convert any DOM tree to a Figma clipboard payload, in the browser.

如何安装 @figit/dom-to-figma?

在项目目录运行 npm install @figit/dom-to-figma,或使用 pnpm add / yarn add / bun add。

@figit/dom-to-figma 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@figit/dom-to-figma 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@figit/dom-to-figma 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@figit/dom-to-figma 可以商用吗?

@figit/dom-to-figma 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@figit/dom-to-figma 的下载量有多少?

根据 npm 官方下载统计,@figit/dom-to-figma 在 2026/10/15 – 2026/11/13 这 30 天内被下载 30,977 次,日均约 1,033 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@figit/dom-to-figma 还在维护吗?

最新版本 0.2.4 发布于 2026/08/22(2 个月前);至今共发布 8 个版本,其中过去 12 个月发布了 8 个;首次发布于 2026/05/19。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。