Hướng dẫn xây Design Tokens trong Penpot theo DTCG: tạo token, alias, công thức, remap, theme và workflow đồng bộ thiết kế với code.

1:04 ước tính · Chưa có giọng vi-VN
Một design system thường không hỏng vì thiếu màu đẹp hay component tốt. Nó hỏng khi cùng một quyết định thiết kế được lưu ở quá nhiều nơi: mã màu nằm trong file thiết kế, khoảng cách nằm trong tài liệu bàn giao, border radius nằm trong CSS và một phiên bản khác lại được designer nhớ bằng kinh nghiệm. Chỉ cần đổi màu thương hiệu hoặc điều chỉnh thang spacing, cả đội phải tìm và sửa hàng chục giá trị rời rạc. Penpot Design Tokens giải quyết đúng lớp vấn đề này bằng cách biến màu sắc, kích thước, khoảng cách, độ bo, typography và nhiều thuộc tính giao diện thành dữ liệu có tên, có quan hệ và có thể chia sẻ giữa thiết kế với code.
Bài hướng dẫn này tập trung vào cách xây một hệ token có thể dùng thật: bắt đầu từ token gốc, tạo alias ngữ nghĩa, dùng công thức để sinh scale, đổi tên an toàn bằng Remap và áp dụng token đúng thuộc tính trong giao diện Penpot. Mục tiêu không phải tạo thật nhiều token, mà là xây một nguồn sự thật duy nhất đủ dễ hiểu để designer dùng hằng ngày và đủ có cấu trúc để developer đưa vào sản phẩm.
Token là một cặp tên–giá trị đại diện cho một quyết định thiết kế. Thay vì ghi trực tiếp #2563EB vào từng nút, đội ngũ có thể tạo token gốc color.blue.600, sau đó tạo token ngữ nghĩa color.action.primary tham chiếu tới màu gốc. Thiết kế vẫn hiển thị đúng màu xanh, nhưng ý nghĩa của màu đã được tách khỏi giá trị kỹ thuật. Khi cần đổi màu hành động chính, đội chỉ sửa một điểm thay vì dò từng màn hình.
Giá trị của token không chỉ là màu. Penpot hỗ trợ nhiều nhóm thuộc tính phục vụ design system như dimension, spacing, sizing, border radius, stroke width, opacity, rotation, typography và shadow. Điểm quan trọng là các token có thể tham chiếu lẫn nhau. Nhờ đó, hệ thống không còn là danh sách biến rời rạc mà trở thành một đồ thị quan hệ: token nền tảng cấp giá trị cho token ngữ nghĩa, còn token ngữ nghĩa được áp dụng vào component và giao diện.
Penpot là nền tảng thiết kế mã nguồn mở, có thể dùng trên dịch vụ web hoặc self-host. Repository chính thức sử dụng giấy phép MPL-2.0, không bị archived và vẫn phát triển tích cực. Bản phát hành 2.17.0 tiếp tục cải thiện việc hiển thị và lan truyền token. Kiến trúc cốt lõi sử dụng Clojure và ClojureScript, đồng thời thiết kế được biểu diễn bằng các chuẩn web như SVG, CSS, HTML và JSON. Đây là nền tảng phù hợp khi đội sản phẩm muốn giảm khoảng cách giữa file thiết kế và implementation thay vì coi handoff là bước xuất ảnh cuối quy trình.
Penpot xây Design Tokens theo định dạng của W3C Design Tokens Community Group, thường được gọi tắt là DTCG. Giá trị thực tế của lựa chọn này nằm ở khả năng trao đổi dữ liệu. Khi token tuân theo cấu trúc phổ biến, đội ngũ có thể xuất JSON, đưa vào pipeline chuyển đổi và sinh biến cho CSS, Sass, JavaScript, Android hoặc iOS mà không phải phát minh một schema riêng cho từng dự án.
DTCG không tự động bảo đảm design system tốt. Nó chỉ tạo một ngôn ngữ chung. Chất lượng vẫn phụ thuộc vào cách đặt tên, phân lớp và quản lý thay đổi. Một file JSON có hàng nghìn token nhưng không thể giải thích token nào dành cho background, token nào dành cho text và token nào sắp bị loại bỏ vẫn là một hệ thống khó vận hành. Vì vậy, trước khi mở bảng Tokens, đội nên thống nhất ba tầng cơ bản:
Không phải dự án nào cũng cần đủ ba tầng. Một sản phẩm nhỏ có thể bắt đầu với core và semantic. Component token chỉ nên xuất hiện khi giúp kiểm soát biến thể hoặc theme rõ ràng; nếu tạo token riêng cho mọi thuộc tính của mọi component ngay từ đầu, hệ thống sẽ trở nên nặng hơn chính các giá trị hard-code mà nó thay thế.
Tên token nên đọc được từ rộng đến cụ thể. Một cấu trúc dễ duy trì có thể là category.role.state cho semantic token và category.family.step cho core token. Ví dụ: color.blue.600, color.text.muted, spacing.layout.lg hoặc radius.control.md. Dấu chấm tạo namespace, giúp danh sách có thứ bậc và giảm khả năng trùng tên.
Tránh dùng tên gắn với giá trị hiện tại như button.blue hoặc card.16px. Những tên này mất ý nghĩa ngay khi thương hiệu đổi màu hoặc hệ spacing được điều chỉnh. Cũng không nên dùng tên theo vị trí màn hình như homepage.left.gray, vì cùng quyết định thiết kế có thể được tái sử dụng ở nhiều luồng khác. Tên tốt mô tả vai trò ổn định hơn giao diện hiện tại.
Một quy tắc thực tế là người mới tham gia dự án phải đoán được token dùng ở đâu mà không mở từng màn hình. Nếu color.surface.raised và color.text.secondary đã đủ rõ, tài liệu chỉ cần bổ sung giới hạn hoặc ví dụ. Nếu tên token buộc người dùng hỏi tác giả mới hiểu, cấu trúc chưa hoàn thành.

Trong bảng Tokens, chọn nhóm Dimension và nhấn dấu cộng để tạo token. Penpot yêu cầu tên, giá trị và cho phép thêm mô tả. Một token thử nghiệm phù hợp là dimension.small với giá trị 64px. Sau khi nhập giá trị, giao diện hiển thị resolved value để người dùng kiểm tra kết quả trước khi lưu.
Ở dự án thật, không nên bắt đầu bằng một con số ngẫu nhiên. Hãy chọn một scale phục vụ nhu cầu sản phẩm. Với giao diện web, đội có thể có thang primitive như dimension.2, dimension.4, dimension.8, dimension.12, dimension.16 và dimension.24. Sau đó tạo token ngữ nghĩa như spacing.control.inline hoặc spacing.section.block để người thiết kế không cần nhớ số nào dùng cho mục đích nào.
Phần Description nên ghi quy tắc sử dụng, không lặp lại tên. “Khoảng cách giữa icon và label trong control nhỏ” hữu ích hơn “Small spacing token”. Với token có ràng buộc accessibility hoặc layout, mô tả có thể nêu thêm phạm vi: dùng cho màn hình desktop, không dùng thay touch target, hoặc chỉ áp dụng cho khoảng cách nội bộ.
Dimension token cần đơn vị phù hợp với nơi sử dụng. px dễ hiểu trong thiết kế giao diện, nhưng đội làm web có thể dùng rem khi muốn scale theo font gốc. Điều quan trọng là không trộn đơn vị tùy hứng trong cùng một scale. Resolved value cho biết Penpot đã diễn giải giá trị ra sao; hãy kiểm tra trường này trước khi lưu, đặc biệt khi token chứa alias hoặc phép tính.

Alias là token tham chiếu tới token khác bằng dấu ngoặc nhọn. Nếu dimension.small có resolved value là 64, token spacing.small có thể dùng giá trị {dimension.small}. Khi dimension gốc đổi, spacing alias cũng đổi theo. Đây là cơ chế cốt lõi để primitive và semantic token không bị tách rời.
Alias đặc biệt hữu ích với theme. Ví dụ, color.gray.950 có thể được gán cho color.text.primary trong light theme, còn dark theme trỏ semantic token đó sang color.gray.50. Component chỉ dùng color.text.primary; nó không cần biết theme hiện tại đang chọn màu thô nào.
Tuy nhiên, chuỗi alias quá dài làm việc truy vết trở nên khó khăn. Nếu component token tham chiếu semantic token, semantic token lại tham chiếu alias trung gian rồi mới tới primitive, một thay đổi nhỏ có thể khó dự đoán. Với đa số đội nhỏ, hai hoặc ba tầng là đủ. Hãy giữ đường dẫn quan hệ ngắn và dùng mô tả để giải thích mục đích của lớp trung gian.
Tham chiếu token có phân biệt chữ hoa và chữ thường. {color.brand.primary} không tương đương {Color.Brand.Primary}. Đội nên thống nhất viết thường, dùng dấu chấm cho namespace và tránh khoảng trắng. Quy tắc này vừa giảm lỗi trong Penpot vừa thuận lợi khi token được đưa sang code và xử lý bằng công cụ tự động.

Token số trong Penpot có thể dùng phép toán. Ví dụ, border.radius.lg có thể nhận giá trị {border.radius.md} * 2. Nếu token medium bằng 4, giá trị đã resolve của large sẽ bằng 8. Khi base scale đổi, các bước phụ thuộc được tính lại thay vì giữ những con số cũ.
Các toán tử cơ bản gồm cộng, trừ, nhân, chia, modulo và lũy thừa. Penpot cũng hỗ trợ những hàm như round(), min(), max(), sqrt() và pow(). Trong workflow thực tế, hàm làm tròn rất hữu ích khi scale dùng hệ số tạo ra số thập phân, còn min() và max() giúp đặt giới hạn an toàn.
Công thức nên phục vụ một quy luật có thể giải thích. Không nên biến token thành bảng tính phức tạp chỉ vì công cụ cho phép. Nếu designer không thể nhìn công thức và hiểu quan hệ, hãy cân nhắc tạo giá trị rõ ràng hơn. Mục tiêu là giảm công việc lặp và giữ scale nhất quán, không phải giấu quyết định thiết kế sau biểu thức khó đọc.
Đội có thể tạo spacing.base bằng 4, sau đó xây spacing.2 bằng {spacing.base} * 2, spacing.3 bằng {spacing.base} * 3 và tiếp tục theo nhu cầu. Semantic token như spacing.control.gap có thể trỏ tới {spacing.2}, còn spacing.section.gap trỏ tới một bước lớn hơn. Khi cần tăng mật độ hoặc điều chỉnh scale, primitive thay đổi nhưng tên semantic vẫn giữ nguyên.

Đặt tên token hiếm khi hoàn hảo ngay lần đầu. Sản phẩm phát triển, ngôn ngữ nội bộ thay đổi và một token ban đầu tưởng là “global” có thể cần tách theo theme. Nếu đổi tên mà bỏ qua các tham chiếu, alias hoặc layer đang dùng tên cũ sẽ bị đứt. Penpot cung cấp Remap để cập nhật các tham chiếu khi token được đổi tên.
Khi sửa tên token có liên kết, hộp thoại Remap cho biết những layer và reference dùng tên cũ sẽ được cập nhật. Chọn remap khi đây là thao tác đổi tên cùng ý nghĩa. Nếu token mới mang ý nghĩa khác, không nên dùng remap để che một thay đổi semantic; hãy tạo token mới, chuyển dần nơi sử dụng rồi deprecate token cũ.
Trước khi remap token ảnh hưởng rộng, đội nên kiểm tra ít nhất ba nhóm: màn hình dùng component cũ, theme khác và file đang tiêu thụ library. Với thay đổi lớn, ghi một changelog ngắn gồm tên cũ, tên mới, lý do và người phụ trách. Điều này giúp developer đối chiếu pull request đổi biến trong code với thay đổi phía thiết kế.
Token đã xuất hiện trong sản phẩm không nên bị xóa đột ngột. Một cách an toàn là đổi mô tả thành “deprecated”, chỉ rõ token thay thế và đặt thời điểm loại bỏ. Sau đó tìm toàn bộ nơi sử dụng, chuyển sang token mới và chỉ xóa khi cả design lẫn code không còn reference. Quy trình này chậm hơn một cú xóa, nhưng giảm nguy cơ giao diện cũ bị mất màu hoặc spacing mà không ai nhận ra.

Ngoài bảng Tokens, Penpot cho phép gán token ngay tại những trường tương thích trong Design sidebar. Ở trường kích thước, người thiết kế có thể mở danh sách sizing token đang active và chọn breakpoint hoặc giá trị phù hợp. Một pill hiển thị token đã gán, nhờ đó người review biết thuộc tính đang dùng quyết định hệ thống chứ không phải số nhập tay.
Cách gán tại sidebar giúp token đi vào workflow tự nhiên. Designer không cần liên tục chuyển qua bảng Tokens để nhớ tên, còn danh sách chỉ hiển thị loại token phù hợp với trường hiện tại. Khi cần ngoại lệ, có thể detach token để trở lại giá trị tùy chỉnh. Tuy vậy, ngoại lệ nên được dùng có chủ đích và được giải thích trong review; quá nhiều thuộc tính detach là tín hiệu scale hiện tại chưa đáp ứng sản phẩm.
Với multi-selection, hãy kiểm tra các layer có cùng token hay chỉ có cùng resolved value. Hai phần tử cùng hiển thị 16px nhưng một phần tử dùng spacing.control.padding, phần còn lại hard-code 16px vẫn là hai trạng thái quản trị khác nhau. Review design system phải nhìn vào liên kết token, không chỉ nhìn kết quả trên canvas.

Border radius token có thể áp dụng cho toàn bộ góc hoặc từng góc riêng. Menu ngữ cảnh cho phép chọn Top Left, Top Right, Bottom Left và Bottom Right. Khả năng này hữu ích với panel gắn cạnh màn hình, nhóm card nối nhau hoặc control có một phía tiếp giáp thành phần khác.
Đừng xây thang radius chỉ theo các số 2, 4, 8, 12 rồi để mỗi người tự chọn. Hãy bổ sung semantic token như radius.control, radius.card, radius.overlay và radius.pill. Primitive vẫn chịu trách nhiệm cho scale, còn semantic token giải thích vai trò. Nếu thương hiệu thay đổi từ hình học sắc sang mềm hơn, đội có thể cập nhật mapping mà không sửa từng component.
Radius cũng cần được kiểm tra cùng kích thước component. Một nút cao 32px với radius quá lớn có thể vô tình trở thành pill, trong khi card lớn dùng cùng giá trị lại gần như vuông. Token không thay thế đánh giá thị giác; nó giúp đánh giá đó được áp dụng nhất quán.

Khi tạo color token, Penpot cung cấp color picker và nhiều cách nhập màu như Hex, RGB, RGBA, ARGB, HSL hoặc HSLA. Hộp thoại hiển thị resolved value để xác nhận màu cuối. Với primitive palette, tên có thể dựa trên family và step, chẳng hạn color.blue.100 đến color.blue.900. Với semantic layer, tên nên dựa trên chức năng như color.surface.default, color.text.muted hoặc color.feedback.negative.
Không nên tạo một semantic token cho mỗi mã màu đang có trong mockup. Hãy bắt đầu từ các vai trò giao diện thật sự: background, surface, text, icon, border, action và feedback. Sau đó kiểm tra mỗi vai trò ở các trạng thái hover, focus, disabled, selected và error. Nếu hai trạng thái luôn dùng cùng quyết định, chúng có thể chia sẻ token; nếu hành vi cần thay đổi độc lập, tách token sẽ an toàn hơn.
Theme là nơi alias thể hiện giá trị rõ nhất. Cùng một token color.surface.default có thể trỏ tới primitive sáng trong light theme và primitive tối trong dark theme. Component không cần nhân đôi chỉ để đổi màu. Khi review, hãy kiểm tra contrast, elevation và trạng thái tương tác ở từng theme thay vì giả định đảo màu là đủ.
Token màu không tự bảo đảm accessibility. Đội vẫn phải đo contrast giữa text và surface, kiểm tra trạng thái focus, không dùng màu làm tín hiệu duy nhất và thử giao diện ở chế độ high contrast khi sản phẩm hỗ trợ. Design token giúp sửa vấn đề theo hệ thống: nếu màu text phụ không đạt contrast, cập nhật mapping có thể cải thiện hàng loạt màn hình cùng lúc. Có thể đối chiếu thêm cách cân bằng hình thức, typography và khả năng tiếp cận trong bài Material 3 Expressive cho UI/UX.

Color token có thể gán cho Fill hoặc Stroke. Nhấp theo hành vi mặc định sẽ áp dụng token làm fill; menu ngữ cảnh cho phép chọn stroke. Hai thuộc tính có thể dùng cùng primitive nhưng nên cân nhắc semantic token khác nhau. color.surface.brand và color.border.brand có thể cùng resolve về một màu ở hiện tại, nhưng khả năng thay đổi độc lập trong tương lai là lý do để tách vai trò.
Khi audit file cũ, hãy tìm các màu có cùng mã nhưng được dùng cho nhiều vai trò khác nhau. Đừng gom tất cả vào một token chỉ vì chúng trùng giá trị. Ngược lại, các mã gần giống nhau nhưng phục vụ cùng vai trò có thể là dấu hiệu drift cần chuẩn hóa. Quyết định gom hay tách phải dựa trên ý nghĩa và quyền thay đổi, không chỉ dựa trên eyedropper.
Một đội nhỏ không cần dừng dự án để xây design system hoàn chỉnh. Có thể triển khai theo từng lát cắt:
Phương pháp theo lát cắt tạo phản hồi sớm. Đội nhanh chóng biết quy tắc đặt tên có dễ dùng không, scale có thiếu bước nào và semantic layer có quá trừu tượng hay không. Nó cũng tránh tình trạng mất nhiều tuần xây thư viện lý tưởng nhưng không khớp UI đang vận hành.
Không nhất thiết khóa toàn bộ token cho một người, nhưng cần xác định ai duyệt primitive, ai duyệt semantic và thay đổi nào phải đi qua review liên chức năng. Đổi description ít rủi ro hơn đổi resolved value của token đang dùng ở hàng trăm layer. Có thể chia thay đổi thành patch, minor và major giống tư duy versioning: sửa mô tả; thêm token không phá cũ; hoặc đổi/xóa token ảnh hưởng consumer.
Token chỉ đạt giá trị lớn nhất khi design và code không duy trì hai danh sách riêng. Penpot cho phép nhập và xuất token ở dạng JSON theo hướng DTCG. Đội có thể lưu file token trong repository, review thay đổi bằng pull request và dùng công cụ build để chuyển sang định dạng của từng nền tảng.
Quy trình không nhất thiết phải tự động hoàn toàn ngay từ ngày đầu. Một bước export có kiểm soát, commit vào repository và review diff đã tốt hơn việc developer chép mã màu từ màn hình. Khi pipeline trưởng thành, đội có thể thêm kiểm tra schema, phát hiện reference bị thiếu, chặn token trùng tên và sinh package versioned cho nhiều ứng dụng.
Cần xác định nguồn sự thật trước. Nếu Penpot là nơi tác giả chỉnh token, repository nên nhận bản export và không cho sửa giá trị thủ công ở file sinh ra. Nếu repository là nguồn chính, đội phải có quy trình import trở lại Penpot. Hai chiều cùng cho phép chỉnh mà không có cơ chế hòa giải sẽ tạo xung đột và làm mất niềm tin vào hệ thống.
Không phải giá trị nào cũng xứng đáng trở thành token. Một kích thước chỉ xuất hiện trong illustration hoặc layout đặc biệt có thể giữ cục bộ. Token nên đại diện cho quyết định lặp lại, cần đồng bộ hoặc có khả năng thay đổi theo theme. Quá nhiều token làm danh sách khó tìm và khiến người dùng quay lại hard-code.
Palette blue.100–900 hữu ích cho người xây hệ thống nhưng chưa trả lời designer nên dùng màu nào cho text phụ hoặc nút chính. Semantic token chuyển scale kỹ thuật thành ngôn ngữ sản phẩm. Nếu mọi component đều chọn primitive trực tiếp, việc đổi thương hiệu vẫn đòi hỏi review thủ công.
Tạo hàng trăm token như button.primary.padding.left ngay từ đầu dễ khóa design system vào cấu trúc component hiện tại. Hãy ưu tiên token dùng chung, sau đó chỉ thêm component token khi cần theme, state hoặc quyền thay đổi độc lập. Một token phải giải quyết vấn đề quản trị cụ thể, không phải chỉ sao chép cây layer.
Thay token trên một màn hình mẫu chưa chứng minh hệ thống an toàn. Hãy kiểm tra component variants, màn hình cũ, theme, responsive breakpoint và code đang dùng package token. Remap và changelog chỉ có ý nghĩa khi đội biết consumer nào phải được cập nhật.
Designer làm sản phẩm nhiều màn hình sẽ hưởng lợi từ semantic token và theme. Design system team có thể dùng alias, remap và JSON để quản trị thay đổi. Developer có được dữ liệu cấu trúc thay cho việc đọc giá trị bằng mắt. Solopreneur hoặc nhóm nhỏ cũng hưởng lợi, nhưng nên bắt đầu gọn: một palette, một spacing scale, typography cơ bản và các semantic token quan trọng nhất.
Penpot đặc biệt đáng cân nhắc với tổ chức muốn self-host, kiểm soát hạ tầng thiết kế hoặc ưu tiên chuẩn web mở. Tuy vậy, chuyển công cụ không tự giải quyết quy trình. Nếu đội không thống nhất ownership, naming và review, design token trong bất kỳ nền tảng nào cũng có thể biến thành một danh sách biến khó hiểu.
Token lưu quyết định thiết kế ở dạng dữ liệu có tên. Style thường gom một nhóm thuộc tính trình bày để áp dụng nhanh. Component lưu cấu trúc và hành vi tái sử dụng. Một component có thể dùng style, còn cả style và component đều có thể lấy giá trị từ token.
Không. Dự án nhỏ thường chỉ cần core và semantic. Chỉ thêm component token khi một component cần quyền thay đổi độc lập hoặc có nhiều state/theme phức tạp. Ít tầng nhưng rõ quan hệ tốt hơn nhiều tầng không ai hiểu.
Có thể dùng số cho primitive scale như blue.600 hoặc spacing.4. Semantic token nên dùng vai trò như text.primary hoặc surface.raised. Tránh đưa giá trị vật lý như 16px vào tên vì giá trị có thể đổi.
Không. Remap phù hợp khi đổi tên mà giữ nguyên ý nghĩa. Nếu ý nghĩa, phạm vi hoặc contract thay đổi, hãy tạo token mới, chuyển consumer, đánh dấu token cũ là deprecated rồi mới xóa.
Không. Token giúp áp dụng và sửa quyết định nhất quán, nhưng đội vẫn phải đo contrast, kiểm tra focus, trạng thái disabled, màu feedback và cách giao diện hoạt động với công nghệ hỗ trợ. Accessibility là tiêu chí thiết kế và kiểm thử, không phải thuộc tính tự sinh từ token.
Penpot Design Tokens đáng giá nhất khi được dùng như một hệ thống quản trị quyết định, không phải bảng màu có tên. Hãy bắt đầu với cấu trúc nhỏ, phân biệt primitive với semantic, dùng alias để tạo quan hệ, chỉ dùng công thức cho quy luật rõ ràng và remap có kiểm soát khi đổi tên. Sau đó áp dụng token trực tiếp vào thuộc tính, review consumer và đưa JSON vào quy trình phát triển.
Nếu cần một điểm khởi đầu thực tế, hãy chọn một luồng sản phẩm, thay toàn bộ màu, spacing và radius lặp lại bằng token rồi thử đổi theme. Những điểm bị đứt sẽ chỉ ra ngay phần nào của naming, alias hoặc ownership chưa đủ rõ. Đó là cách design system trưởng thành từ nhu cầu thật thay vì từ một danh sách token được xây trong phòng kín.








Đăng ký miễn phí, lấy link riêng và giới thiệu NextGZ cho người cần học tiếng Trung hoặc Digital Art.
Cộng đồng thực chiến
Tham gia nhóm để nhận tài nguyên, cập nhật công cụ và trao đổi cách xây dựng digital business cùng AI.
Tham gia nhóm ZaloCộng đồng sáng tạo
Kết nối với cộng đồng Digital Art, chia sẻ tác phẩm và học hỏi quy trình sáng tạo mới.
Tham gia DiscordCộng đồng thực chiến
Tham gia nhóm để nhận tài nguyên, cập nhật công cụ và trao đổi cách xây dựng digital business cùng AI.
Tham gia nhóm ZaloCộng đồng sáng tạo
Kết nối với cộng đồng Digital Art, chia sẻ tác phẩm và học hỏi quy trình sáng tạo mới.
Bình luận
0 bình luận
Đăng nhập để tham gia thảo luận cùng cộng đồng!
Đăng nhập ngayĐang tải bình luận...