Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn đang làm việc trong một team thiết kế của một ngân hàng số tại Việt Nam. Một ngày đẹp trời, sếp bảo: "Đổi màu thương hiệu từ xanh dương sang xanh lá đi, ban lãnh đạo vừa duyệt nhận diện mới." Nếu file Figma của bạn có 200 màn hình, mỗi nút bấm, mỗi link, mỗi biểu tượng đều được tô màu thủ công bằng mã hex #1E6FD6, thì bạn sẽ phải ngồi sửa từng cái một — và chắc chắn sẽ bỏ sót vài chỗ. Đội ngũ developer cũng vậy: họ phải tìm-và-thay (find & replace) trên hàng nghìn dòng code, rủi ro sai sót cực cao.
Bây giờ hãy tưởng tượng kịch bản thứ hai: bạn chỉ cần đổi đúng MỘT giá trị ở một nơi duy nhất, và toàn bộ 200 màn hình tự động cập nhật. Đó chính là sức mạnh của token architecture — kiến trúc token được tổ chức theo lớp.
Ở Bài 15, chúng ta đã làm quen với khái niệm design token như một "biến lưu trữ giá trị thiết kế". Nhưng nếu chỉ dừng ở việc tạo ra một danh sách token phẳng (flat list), bạn sẽ nhanh chóng rơi vào hỗn loạn khi hệ thống lớn dần. Bài 16 này đi sâu vào câu hỏi quan trọng nhất: làm thế nào để TỔ CHỨC token thành một kiến trúc bền vững? Câu trả lời nằm ở mô hình ba lớp — Primitive, Semantic, và Component. Đây là kỹ năng phân biệt một designer "biết dùng token" với một designer "xây được design system thật sự dùng được ở quy mô doanh nghiệp".
Khái niệm cốt lõi
Token architecture là cách chúng ta phân tầng các design token thành những lớp có vai trò khác nhau, mỗi lớp tham chiếu (reference) đến lớp bên dưới nó. Hãy nghĩ về nó như một chuỗi cung ứng: nguyên liệu thô → bán thành phẩm → sản phẩm hoàn chỉnh. Có ba lớp chính.
Lớp 1 — Primitive token (token nguyên thủy)
Đây là lớp nền tảng, chứa các giá trị thô (raw value) không mang ý nghĩa sử dụng. Một primitive token chỉ đơn thuần đặt tên cho một giá trị cụ thể.
Ví dụ với màu sắc:
blue-500: #3B82F6blue-600: #2563EBgray-100: #F3F4F6gray-900: #111827
space-1: 4pxspace-2: 8pxspace-4: 16px
blue-500 chỉ là "màu xanh dương ở độ đậm 500", nó không biết rằng nó sẽ được dùng làm màu nút bấm hay màu link. Đây thường là một bảng màu (palette) đầy đủ — bạn có thể có 10 sắc độ cho mỗi tông màu, dù thực tế chỉ dùng vài cái. Primitive token giống như hộp bút chì màu đầy đủ 48 màu của bạn: bạn sở hữu tất cả, nhưng chưa quyết định màu nào vẽ bầu trời, màu nào vẽ cỏ.Lớp 2 — Semantic token (token ngữ nghĩa)
Đây là lớp gán ý nghĩa và mục đích sử dụng. Semantic token không chứa giá trị thô — nó trỏ tới một primitive token. Tên của nó mô tả vai trò, ngữ cảnh, ý đồ.
Ví dụ:
color-primary: {blue-500}— màu chủ đạo của thương hiệucolor-text-default: {gray-900}— màu chữ mặc địnhcolor-background-surface: {gray-100}— màu nền của bề mặtcolor-border-error: {red-500}— màu viền khi có lỗispace-inset-md: {space-4}— khoảng đệm bên trong vừa phải
{...} là quy ước phổ biến (theo chuẩn W3C Design Tokens) để biểu thị "tham chiếu tới token khác", còn gọi là alias. Đây mới là lớp mà phần lớn designer và developer làm việc hằng ngày. Khi bạn thiết kế, bạn không nghĩ "nút này màu blue-500" — bạn nghĩ "nút này dùng màu primary". Sự khác biệt tinh tế đó chính là chìa khóa của khả năng bảo trì. Quay lại câu chuyện ngân hàng đổi màu thương hiệu ở đầu bài: bạn chỉ cần đổi color-primary từ trỏ tới {blue-500} sang trỏ tới {green-500}, mọi thứ "primary" trên toàn hệ thống lập tức đổi theo.Lớp 3 — Component token (token cấp thành phần)
Đây là lớp chuyên biệt hóa cho một component cụ thể. Component token trỏ tới semantic token (hoặc đôi khi tới primitive), và mô tả chính xác một thuộc tính của một bộ phận giao diện.
Ví dụ với nút bấm (button):
button-primary-background: {color-primary}button-primary-text: {color-text-on-primary}button-primary-background-hover: {color-primary-hover}button-radius: {radius-md}
button-radius mà không đụng tới radius-md chung. Lưu ý: không phải lúc nào cũng cần lớp component. Với hệ thống nhỏ, nhiều team bỏ qua nó để tránh phình to. Đây là lớp "tùy chọn theo nhu cầu".Luồng tham chiếu một chiều
Nguyên tắc vàng: token chỉ tham chiếu xuống dưới, không bao giờ ngược lên hay ngang hàng.
Component → Semantic → Primitive → Giá trị thô
button-primary-background → color-primary → blue-500 → #3B82F6
Khi component cần màu, nó hỏi semantic; semantic hỏi primitive; primitive trả về mã hex. Chuỗi này giúp bạn thay đổi ở bất kỳ tầng nào mà hiệu ứng lan tỏa có kiểm soát.
Tình huống thực tế
Ví dụ 1 — Tiki tái cấu trúc token khi mở rộng
Giả sử một sàn thương mại điện tử lớn như Tiki bắt đầu với một file token phẳng: developer khai báo trực tiếp mainGreen: #1A94FF (thực ra là xanh dương đặc trưng) và dùng khắp nơi. Ban đầu mọi thứ ổn vì chỉ có 30 màn hình. Nhưng khi mở rộng sang TikiNOW, Tiki Trading, và mảng tài chính, họ có hơn 400 màn hình và 5 nhóm developer khác nhau.
Vấn đề bùng nổ khi marketing yêu cầu chiến dịch sale 11/11 dùng tông màu cam rực rỡ tạm thời. Vì màu được hard-code khắp nơi, không ai dám đụng vào. Họ quyết định tái cấu trúc theo ba lớp: tạo palette primitive đầy đủ (blue-100 đến blue-900, orange-100 đến orange-900), rồi định nghĩa semantic color-brand-primary. Sau đó, khi cần chạy theme sale, họ tạo một "mode" cho mùa lễ hội, chỉ trỏ color-brand-primary sang {orange-500}.
Bài học: Flat token chấp nhận được khi nhỏ, nhưng sẽ trở thành nợ kỹ thuật khi scale. Lớp semantic là "lớp cách ly" giúp thay đổi an toàn.
Ví dụ 2 — Một fintech Đông Nam Á và bài toán dark mode
Một công ty fintech ở Singapore (gọi là PayWave) muốn ra mắt dark mode. Designer ban đầu hoảng loạn vì phải thiết kế lại 150 màn hình. Nhưng vì họ đã xây token theo lớp, công việc trở nên đơn giản đến bất ngờ.
Họ giữ nguyên lớp primitive (palette không đổi — gray-50 vẫn là #FAFAFA). Họ tạo hai chế độ cho lớp semantic:
- Light mode:
color-background-surface: {gray-50},color-text-default: {gray-900} - Dark mode:
color-background-surface: {gray-900},color-text-default: {gray-50}
color-text-default) tự động hiển thị đúng trong cả hai chế độ mà không sửa một dòng nào ở lớp component. Thời gian ước tính giảm từ 3 tuần xuống còn 4 ngày.Bài học: Khi lớp semantic được thiết kế tốt, các tính năng như theming và dark mode gần như "miễn phí" — bạn chỉ hoán đổi giá trị ở một tầng. (Chúng ta sẽ đào sâu chủ đề multi-brand & theming ở Bài 17.)
Ví dụ 3 — Startup nhỏ và cái bẫy over-engineering
Một startup giáo dục tại TP.HCM với team chỉ 2 designer đọc về Atomic Design và token architecture, rồi quyết định xây đủ ba lớp với cả component token chi tiết cho từng nút. Kết quả: họ có 600 token cho một sản phẩm chỉ 20 màn hình. Mỗi lần đổi một màu, họ phải lần theo bốn tầng tham chiếu, và bạn designer mới vào mất cả tuần mới hiểu hệ thống.
Họ rút gọn lại: giữ primitive và semantic, bỏ hoàn toàn lớp component. Component lấy thẳng giá trị từ semantic. Số token giảm còn 90, dễ hiểu hơn nhiều.
Bài học: Kiến trúc tốt không phải là kiến trúc nhiều lớp nhất, mà là kiến trúc vừa đủ với quy mô của bạn. Đừng thêm lớp component cho tới khi bạn thực sự cảm thấy đau vì thiếu nó.
Hướng dẫn từng bước
Đây là quy trình xây token architecture từ đầu, áp dụng được trong Figma (dùng Variables) hoặc trong file token JSON.
Bước 1 — Xây lớp primitive trước. Định nghĩa palette màu đầy đủ với hệ thống đặt tên theo sắc độ số (50, 100, 200... 900). Làm tương tự cho spacing, font-size, radius, shadow. Ở bước này, ĐỪNG nghĩ tới mục đích sử dụng — chỉ tạo "kho nguyên liệu". Đặt chúng trong một collection riêng, ví dụ tên là _primitives, và đánh dấu là nội bộ (không cho phép dùng trực tiếp khi thiết kế).
Bước 2 — Định nghĩa lớp semantic theo vai trò. Liệt kê các vai trò mà giao diện của bạn cần: primary, secondary, danger, success, warning; text-default, text-muted, text-on-primary; background-page, background-surface, background-overlay; border-default, border-focus. Mỗi semantic token trỏ tới một primitive. Đây là bước cần tư duy thiết kế nhiều nhất — đặt tên đúng vai trò sẽ quyết định hệ thống dễ dùng hay không.
Bước 3 — Quyết định có cần lớp component không. Đặt câu hỏi: "Có component nào cần giá trị KHÁC với semantic chung không?" Nếu nút bấm dùng đúng color-primary thì KHÔNG cần component token. Chỉ tạo component token khi có nhu cầu chuyên biệt hóa thật sự.
Bước 4 — Thiết lập tham chiếu trong công cụ. Trong Figma, dùng tính năng "alias" của Variables: thay vì gõ giá trị, bạn chọn token khác để trỏ tới. Đảm bảo mọi semantic đều là alias, không phải giá trị thô.
Bước 5 — Áp dụng quy ước đặt tên nhất quán. Một công thức phổ biến: [category]-[role]-[variant]-[state]. Ví dụ color-text-primary-hover. Viết tài liệu ngắn về quy ước này (chủ đề documentation sẽ học kỹ ở Bài 18).
Bước 6 — Kiểm thử bằng một thay đổi giả định. Thử đổi color-primary sang màu khác và quan sát. Nếu toàn bộ giao diện cập nhật đúng và không có chỗ nào "trơ" (do hard-code), kiến trúc của bạn đã hoạt động.
Lỗi thường gặp & mẹo
Lỗi 1 — Đặt tên semantic theo màu thay vì theo vai trò. Một sai lầm kinh điển: tạo semantic token tên color-blue trỏ tới {blue-500}. Khi thương hiệu đổi sang xanh lá, bạn có token tên color-blue nhưng giá trị lại là màu xanh lá — vô lý và gây nhầm lẫn. Mẹo: tên semantic phải mô tả MỤC ĐÍCH (color-primary, color-interactive), không bao giờ mô tả màu sắc cụ thể.
Lỗi 2 — Cho phép designer dùng trực tiếp primitive token. Nếu ai cũng dùng blue-500 thoải mái khi thiết kế, lớp semantic trở nên vô dụng và bạn mất khả năng đổi theme. Mẹo: ẩn hoặc khóa primitive khỏi danh sách chọn trong Figma, chỉ phơi bày semantic cho người thiết kế hằng ngày.
Lỗi 3 — Tạo quá nhiều lớp tham chiếu lồng nhau. Chuỗi như component → semantic → semantic khác → primitive khiến việc debug rất mệt. Mẹo: giữ độ sâu tối đa 3 bước. Mỗi lớp chỉ trỏ xuống lớp ngay dưới.
Lỗi 4 — Quên các state (trạng thái). Nhiều người chỉ định nghĩa màu mặc định mà quên hover, active, disabled, focus. Mẹo: với mỗi vai trò tương tác, hãy chuẩn bị bộ trạng thái ngay từ đầu.
Lỗi 5 — Palette primitive quá nghèo nàn. Chỉ có blue-500 mà không có các sắc độ lân cận khiến bạn không tạo được hiệu ứng hover (thường cần đậm/nhạt hơn một bậc). Mẹo: tạo tối thiểu 9 sắc độ cho mỗi tông màu cốt lõi.
Mẹo tổng quát: Hãy nghĩ về primitive như "từ vựng", semantic như "ngữ pháp", và component như "câu nói chuyên biệt". Một ngôn ngữ tốt cần từ vựng đủ giàu nhưng ngữ pháp phải gọn gàng, nhất quán.
Bài tập thực hành
Bài tập 1 — Phân loại token. Cho danh sách sau, hãy gán nhãn mỗi token thuộc lớp nào (primitive / semantic / component):
red-600: #DC2626color-danger: {red-600}space-3: 12pxcard-padding: {space-inset-lg}color-text-on-danger: {gray-50}
color-primary và kiểm tra xem mọi thứ có cập nhật không.Bài tập 3 — Sửa kiến trúc lỗi. Một đồng nghiệp đưa bạn hệ thống có token color-orange-button: #F97316 dùng trực tiếp trong code. Hãy viết lại nó thành ba lớp đúng chuẩn và giải thích lợi ích.
Bài tập 4 — Quyết định cắt lớp. Cho một dự án landing page tĩnh 5 trang. Bạn có nên dùng lớp component token không? Viết 3 câu lý giải.
Tóm tắt
Token architecture là nghệ thuật phân tầng design token để hệ thống của bạn vừa linh hoạt vừa dễ bảo trì. Ba lớp cốt lõi: Primitive chứa giá trị thô và đặt tên theo chính nó (blue-500: #3B82F6); Semantic gán mục đích sử dụng bằng cách trỏ tới primitive (color-primary: {blue-500}); Component chuyên biệt hóa cho một bộ phận giao diện khi cần (button-background: {color-primary}). Nguyên tắc cốt lõi là tham chiếu một chiều — chỉ trỏ xuống dưới, không lồng quá 3 bước.
Lớp semantic là "lớp cách ly" quan trọng nhất: nó giúp bạn đổi thương hiệu, làm dark mode, chạy chiến dịch theo mùa chỉ bằng cách hoán đổi giá trị ở một tầng. Đừng đặt tên semantic theo màu sắc, đừng cho dùng primitive trực tiếp, và đừng over-engineer — hãy thêm lớp component chỉ khi bạn thật sự cần. Khi nắm vững kiến trúc này, bạn đã sẵn sàng cho những chủ đề nâng cao hơn như multi-brand theming (Bài 17) và viết tài liệu design system (Bài 18).