Import UI từ code vào Figma bằng plugin - đúng token màu, nhanh và thống nhất từ nay về sau
Cách mình đưa UI đang chạy từ code sang Figma bằng một plugin nội bộ - frame auto-layout thật, màu và khoảng cách bind đúng biến của design system, cập nhật theo trang mỗi khi code đổi. Hiện chỉ có mình dùng, team chưa áp dụng.

Mục lục
TL;DR
- Mình tự dựng một quy trình đưa UI đang chạy từ code vào Figma qua plugin: bấm một nút, code hiện ra thành frame auto-layout thật.
- Đúng token: màu, khoảng cách, bo góc bind vào đúng biến semantic của design system; nút, icon, logo là instance thư viện.
- Nhanh: 54 màn hình đọc xong trong dưới một phút; code không đổi thì lần sau chỉ mất vài giây.
- Thống nhất: code là nguồn duy nhất, Figma cập nhật theo trang, không ghi đè frame đã sửa tay, có biên nhận PASS hay FAIL.
- Hiện chỉ có mình dùng, team chưa áp dụng. Chưa bắt hover và tooltip, chưa có dark mode và mobile.
Bối cảnh
Mình cần đưa 54 màn hình kho bài tập của một sản phẩm học trực tuyến lên Figma, trong khi tất cả đã chạy thật trong code. Vẽ tay thì chậm, lệch, và không ai cập nhật nổi khi code đổi.
Chi tiết hơn: flow này gồm trang tổng quan, bốn kho Reading, Listening, Speaking, Writing, kho Full test, mỗi kho vài tab thống kê. Ở team mình khi đó, UI thật sống trong code trước khi nó kịp đẹp trong Figma: Playground (React) là nơi mình dựng và thử màn hình mới, còn Figma là nơi cả team nhìn, bàn và chốt. Vẽ lại 54 màn hình bằng tay mất nhiều ngày, vẽ xong là lệch ngay vì code đổi liên tục, và vẽ tay là chỗ sinh ra sai lệch nhỏ mà không ai nhận ra: nút cao 44 thay vì 40, màu chữ lấy nhầm bậc, khoảng cách 14 thay vì 16.
Nói rõ từ đầu: đây là cách mình tự dựng và hiện chỉ có mình dùng, team chưa áp dụng. Bài này là ghi chép của một người làm, chưa phải quy trình chung.
Vì sao các cách quen thuộc không đủ
Chụp ảnh, plugin HTML sang Figma có sẵn, hay nhờ AI vẽ từng section đều chỉ chụp bề ngoài. Cái mình cần là dịch cấu trúc.
- Chụp màn hình dán vào Figma: nhanh nhất, nhưng là một tấm ảnh chết. Không sửa, không đo, không bind biến, và không ai biết ảnh ứng với bản code nào.
- Plugin HTML sang Figma trên thị trường: ra frame thật nhưng auto-layout nửa vời, màu là hex thô, và không biết design system của mình. Nút thành hình chữ nhật, icon thành vector rời, muốn dùng tiếp phải dọn từng frame.
- Nhờ AI vẽ từng section: hợp với một màn hình mới, nhưng 54 màn hình thì quá chậm và không lặp lại được khi code đổi.
Cách mình làm: dịch DOM thành auto-layout, rồi để plugin dựng
Ba bước chạy nối nhau sau một nút bấm: đọc UI đang chạy, suy ra auto-layout từ số đo, rồi plugin dựng trong Figma và bind biến.
- Đọc UI đang chạy bằng trình duyệt không giao diện: với từng phần tử lấy hình chữ nhật thật và style đã tính (flex hay grid, gap, padding, font, màu dưới dạng tên biến CSS). Chữ gộp theo dòng chảy inline; icon và logo được nhận ra là icon của design system chứ không phải một SVG bất kỳ.
- Suy ra auto-layout từ số đo, CSS chỉ là gợi ý: flex thành hàng hoặc cột, grid thành grid thật của Figma, gap đo được thành item spacing, phần dư thành spacer, con lấp đầy cha thì Fill, con ôm nội dung thì Hug. Mọi container thật đều có auto-layout.
- Plugin trong Figma dựng frame theo cây đó: đặt sizing, bind màu và khoảng cách vào biến thư viện của design system, dựng nút thành instance của Button, icon thành instance thư viện icon, mẫu lặp thành component có variant.
Phía người bấm thì tất cả gói lại thành một nút trong plugin: mở file Figma, bấm Đồng bộ toàn bộ UI, đợi plugin chạy xong, rồi đọc biên nhận PASS hay FAIL ngay trên panel. Người bấm hiện tại là mình.

Panel plugin: chọn trang cần đồng bộ, bấm một nút, xem tiến độ và biên nhận ngay tại chỗ
Lợi thế 1: đúng token màu, không phải chỉ đúng màu
Tên biến CSS và tên biến Figma của design system giống nhau một một, nên frame bind đúng biến semantic thay vì gán một mã hex trông giống.
Ví dụ biến chữ brand trong code là --text-color-brand-primary, trong Figma là text-color/brand/primary. Serializer đọc được tên biến trên phần tử, builder tra đúng biến đó trong thư viện và bind vào paint.
Có một cái bẫy mình từng dính: một số class tiện ích chỉ để lại tên biến palette thô (kiểu primary/PR100), không để lại tên semantic. Bind theo tên thô thì frame trông vẫn đúng màu nhưng sai ý nghĩa, và khi đổi theme hay đổi thang màu thì không đi theo. Giờ builder ưu tiên biến semantic đúng vai trò (chữ, nền, viền, icon), chỉ khi không tra được mới rơi về biến thô, và biên nhận đếm rõ còn bao nhiêu chỗ đang bind thô.
Không chỉ màu: gap, padding và bo góc bind vào biến số của design system (thang spacing, inset, radius theo loại control, surface hay overlay). Nút bấm được nhận ra từ chính công thức class của component Button và dựng thành instance Button trong thư viện với đúng size, tone, icon. Ở lượt đồng bộ đầu tiên của 54 màn hình, hơn 16.000 paint được bind vào biến của design system.
Điều kiện duy nhất: file Figma đích phải bật thư viện biến của design system. Không bật thì frame vẫn dựng đúng, nhưng màu là hex.

Kết quả trong Figma: Selection colors hiển thị tên biến như text-color/neutral/secondary, border-color/neutral/subtle và surface/neutral/primary thay vì chỉ một mã màu.
Lợi thế 2: nhanh, và lần sau còn nhanh hơn
Đọc 54 màn hình mất dưới một phút. Code không đổi thì lần sau cả vòng chỉ vài giây.
Bước đọc chạy song song nhiều tab trình duyệt. Bước dựng trong Figma chạy từng lát ngắn để Figma không bị đơ. Một thư mục 9 file HTML demo tự chứa cũng chỉ mất vài giây để đọc.
Cái làm quy trình thật sự nhanh là lần thứ hai: mỗi trang mang một hash của nội dung, và mỗi frame trong Figma được đóng dấu hash đó. Code không đổi thì bước đọc bị bỏ qua, 54 frame chỉ được kiểm tra rồi giữ nguyên. Code đổi ở hai trang thì đúng hai trang được dựng lại.
Lợi thế 3: thống nhất, vì chỉ có một nguồn
Code là nguồn, Figma là nơi nhìn. Không còn câu hỏi bản nào đúng.
- Cập nhật tại chỗ, không xoá dựng lại: frame giữ vị trí, giữ luôn cả nhóm mình đã gom tay.
- Frame đã sửa tay không bị ghi đè: plugin nhận ra vân tay cây đã đổi, dựng bản mới ngay bên cạnh với đuôi “mới” và báo xung đột để mình quyết định giữ bản nào.
- Mẫu lặp thành component: card trong kho đề thành một component set với variant lấy từ chính thuộc tính trong code (Scope, Size, State), các trang chỉ dùng instance và override chữ, ảnh, màu.
- Có biên nhận đo được: sau mỗi lượt, plugin kiểm tra hash từng frame, node lệch quá 24px, đoạn chữ xuống dòng thêm, màu chưa bind, con thò ra khỏi cha trong instance. PASS hay FAIL hiện thẳng trên panel.
Lợi thế 4: tiện từ nay về sau
Quy trình không dừng ở một dự án: tự chạy được, nhận cả HTML tĩnh, và page Import cứ đi theo code.
- Tự chạy được, không cần dev hay AI đứng cạnh: import plugin một lần, mở đúng file, bấm một nút. Hiện mới có mình dùng, team chưa áp dụng; nếu sau này có người muốn thử thì cũng chỉ cần bấy nhiêu bước.
- Không chỉ Playground: một thư mục HTML tĩnh (ví dụ bộ demo giải thích đáp án Reading mình nhận được) đi cùng chuỗi y hệt, mỗi file thành một frame 1440 trong một section riêng.
- Page Import là bản chụp chỉ đọc: muốn thiết kế tiếp thì copy frame sang page thiết kế, page Import tiếp tục đi theo code.
- Thêm mẫu component mới chỉ là thêm một dòng khai báo, không phải sửa code sản phẩm.
Nói cách khác, mỗi màn hình mình dựng bằng code từ nay tự động có mặt trong Figma với đúng token, và giữ đúng như vậy sau mỗi lần code đổi.

Toàn cảnh kết quả import: các màn hình được gom theo từng section, còn Components nằm riêng bên trái để xem lại các mẫu dùng chung.
Giới hạn thật
- Chưa bắt trạng thái hover và tooltip; chỉ trạng thái đang hiển thị lúc đọc được đưa sang.
- Chữ trong Figma rộng hơn Chrome khoảng 4% (font web là subset, Figma dùng font đầy đủ), nên thỉnh thoảng một đoạn dài thêm một dòng. Biên nhận báo, mình chấp nhận thay vì ép letter-spacing.
- Danh sách dài chỉ giữ 3 hàng để frame không dài theo dữ liệu.
- HTML demo dùng hex thô thì màu chưa bind biến cho tới khi được thiết kế lại theo design system.
- Chưa có dark mode và bản mobile.
Điều mình rút ra
Import UI từ code vào Figma chỉ đúng token khi design system đã có tên cho từng thứ, và code thật sự dùng những cái tên đó. Code viết hex thẳng thì không tool nào cứu được. Còn khi token có tên, cùng một tên ở CSS và ở Figma, thì Figma không còn là nơi vẽ lại nữa: nó là nơi nhìn và bàn về UI thật, luôn mới, luôn đúng hệ.