Guideline Component & Mẫu tài liệuComponent Guidelines & Documentation Patterns
Thuộc bộ kiến thức Design System Roadmap.
Tổng quan
Một component chỉ hữu ích ngang với phần guidance đi kèm nó. Cứ thử ship một Select component được code đẹp, prop rõ ràng, accessibility tốt, nhưng không có bất kỳ tài liệu hướng dẫn nào — chỉ trong một quý, hai chuyện sẽ xảy ra: một số team dùng sai nó (nhồi 40 option không được sắp xếp vào một Select, hoặc một form dùng ba pattern input khác nhau cho cùng một loại lựa chọn), và các team khác thì né tránh hoàn toàn, tự viết lại một dropdown gần như y hệt từ đầu vì họ không biết có sẵn component chung, hoặc không tin tưởng nó làm được điều họ cần. Cả hai kết cục đều là những thất bại âm thầm — không ai report bug, code vẫn compile, màn hình vẫn render bình thường — nhưng đó chính là những thất bại mà một design system tồn tại để ngăn chặn. Vì vậy, documentation không phải là thứ “có thì tốt” gắn thêm vào component sau khi đã xong; nó chính là cơ chế mà design system thực sự truyền tải giá trị của mình. Component là artifact; documentation là thứ chuyển giao quá trình ra quyết định đã tạo ra component đó cho mọi consumer tương lai — những người không có mặt trong phòng lúc quyết định được đưa ra.
Note này nói về nửa còn lại, kém hào nhoáng hơn, của việc xây dựng một component trong design system: không phải “làm sao để xây một Select tốt,” mà là “làm sao dạy hai trăm engineer và designer không bao giờ trực tiếp trao đổi với chúng ta cách dùng nó cho đúng, và tin tưởng nó đủ để chọn nó trước khi tự viết cái của riêng mình.” Việc dạy đó diễn ra thông qua một tập hợp các mẫu tài liệu cụ thể — usage guidance, placement guidance, ví dụ do/don’t, tài liệu về size và state, và tài liệu ở cấp pattern cho các composition — mỗi loại trả lời một câu hỏi khác nhau mà consumer đặt ra ngay tại thời điểm họ sắp đưa ra một quyết định về UI.
Cái giá của việc thiếu guidance
| Guidance bị thiếu | Điều gì xảy ra trong thực tế |
|---|---|
| Không có usage guidance (“khi nào dùng cái này thay vì cái kia?”) | Các team đoán mò, và đoán không nhất quán — màn hình này dùng Select cho 3 option, màn hình khác dùng radio buttons cho 12 option |
| Không có placement guidance (“component này nằm ở đâu trên trang?”) | Primary action nằm ở mỗi góc khác nhau trên mỗi form; banner xuất hiện inline ở trang này nhưng ghim trên đầu ở trang khác |
| Không có ví dụ do/don’t | Những cách dùng sai tinh vi (label bị cắt cụt, sai thứ tự ưu tiên của button) lọt lên production vì không có gì cảnh báo trực quan rằng nó sai |
| Không có tài liệu size/state | Engineer tự chế ra variant tùy tiện (“thêm prop tiny vào là được”) vì họ không biết đã có sẵn một size phù hợp |
| Không có tài liệu pattern | Mỗi team tự xây empty state riêng, confirmation dialog riêng từ các component thô, mỗi cái một kiểu và mỗi cái tự giải lại những vấn đề (quản lý focus, tone văn bản) đã được giải quyết một lần trước đó |
Mỗi dòng ở trên mô tả việc tái phát minh hoặc sự thiếu nhất quán tốn thời gian engineering thật sự và làm xói mòn tính mạch lạc của sản phẩm — và mỗi dòng đều có thể ngăn chặn được bằng tài liệu trả lời đúng câu hỏi mà consumer đang đặt ra tại thời điểm sử dụng.
Kiến thức nền tảng
Usage guidance: khi nào dùng component này thay vì một phương án khác
Câu quan trọng nhất trong tài liệu của bất kỳ component nào là câu cho consumer biết khi nào nên dùng nó — và, không kém quan trọng, khi nào không nên, đồng thời chỉ họ đến phương án thay thế đúng. Component hiếm khi tồn tại độc lập; chúng nằm trong những nhóm nhỏ các component giải quyết các vấn đề liên quan với những trade-off khác nhau (Select so với radio group so với combobox, Modal so với Banner inline, Tabs so với Accordion). Không có quy tắc quyết định rõ ràng, engineer sẽ mặc định chọn component nào họ vừa dùng gần đây nhất hoặc tình cờ nhớ được, bất kể nó có phù hợp hay không.
Một phần usage guidance tốt phát biểu quy tắc như một heuristic cụ thể, có thể kiểm chứng được, thay vì lời khuyên mơ hồ kiểu “dùng cái này khi phù hợp.” Một số ví dụ thực tế về pattern này:
| Component | Quy tắc usage tốt | Vì sao nó hiệu quả |
|---|---|---|
Select (dropdown) | Dùng khi có hơn khoảng 5 option và người dùng đã biết mình muốn gì (recognition, không phải comparison) | Đưa ra một ngưỡng số cụ thể và một lý do nhận thức, không chỉ là sở thích |
| Radio buttons | Dùng khi có 2–5 option và người dùng cần so sánh chúng song song trước khi chọn | Đối lập trực tiếp với quy tắc Select ở trên nên hai component không cạnh tranh mơ hồ với nhau |
| Checkbox | Dùng cho một lựa chọn bật/tắt độc lập, hoặc một tập nhỏ các option multi-select độc lập | Phân biệt với radio buttons (loại trừ lẫn nhau) và toggle switch (có hiệu lực ngay lập tức) |
| Toggle switch | Dùng khi thay đổi có hiệu lực ngay, không cần bước “Save” riêng | Điểm khác biệt then chốt so với checkbox trong form là tính tức thời của hiệu lực, không phải kiểu dáng hình thức |
Modal | Dùng cho một tác vụ cần chặn luồng hiện tại và phải được xử lý xong trước khi người dùng tiếp tục (confirmation, một tác vụ ngắn cần tập trung) | Gắn component với một chi phí tương tác (nó chặn mọi thứ khác) để các team không dùng nó theo thói quen |
Banner inline | Dùng cho thông tin theo ngữ cảnh, không chặn luồng, gắn với nội dung trên trang | Đối lập trực tiếp với Modal trên cùng một trục: blocking so với non-blocking |
Tabs | Dùng khi người dùng cần chuyển đổi giữa một số lượng nhỏ (≤ 6–7) các view liên quan, song song có tầm quan trọng tương đương | Chỉ ra failure mode: quá nhiều tab, hoặc dùng tab cho một luồng tuyến tính từng bước (lẽ ra nên là stepper) |
Chú ý pattern lặp lại ở mọi dòng: quy tắc luôn tham chiếu đến một ngưỡng (số lượng option, số lượng tab), một hành vi (hiệu lực tức thời so với trì hoãn, blocking so với non-blocking), hoặc một ý định của người dùng (recognition so với comparison) — một thứ mà người review có thể thực sự kiểm tra trên một màn hình cụ thể, thay vì một phán đoán chủ quan. Đây chính là điều phân biệt usage guidance thực sự hữu ích với một đoạn văn không ai đọc.
Placement guidance: component thuộc về đâu trong một layout
Một loại guidance thứ hai, khác biệt, trả lời không phải “component nào” mà là “ở đâu trên màn hình.” Cùng một button, banner, hay field sẽ hành xử và được hiểu hoàn toàn khác nhau tùy vào vị trí của nó, và những design system bỏ qua placement guidance sẽ có những component đúng riêng lẻ nhưng không nhất quán khi nhìn tổng thể — mỗi form có primary action ở một vị trí khác nhau, mỗi alert xuất hiện ở một góc khác nhau.
Placement guidance thường bao gồm:
- Thứ bậc và mức nhấn mạnh theo vị trí — với hầu hết hướng đọc (trái sang phải, trên xuống dưới), primary action nằm ở góc dưới-phải của form hoặc cuối footer của modal (điểm kết thúc tự nhiên của luồng đọc), với các action phụ/thứ cấp nằm bên trái nó, có trọng lượng thị giác giảm dần. Đảo ngược điều này — đặt action mang tính phá hủy hoặc phụ vào vị trí nổi bật nhất về thị giác — là một lỗi phổ biến, tốn kém mà một quy tắc placement có thể ngăn chặn.
- Phạm vi toàn trang so với inline — một
Bannerhệ thống dùng cho một thông điệp toàn trang, bắt buộc phải thấy (thông báo gián đoạn dịch vụ, cảnh báo toàn hệ thống) thì nên ghim ở đầu trang, trên tất cả nội dung; cùng component thị giác đó dùng để chỉ ra vấn đề với một field hoặc section cụ thể thì nên nằm ngay cạnh section đó, inline, không phải ở đầu trang, vì vị trí truyền tải phạm vi ảnh hưởng. Lẫn lộn hai cái này khiến người dùng hiểu sai mức độ liên quan của thông điệp. - Tính nhất quán của các phần tử lặp lại — link “Cancel” nằm ở đâu so với button “Save,” breadcrumb nằm ở đâu so với tiêu đề trang, ô tìm kiếm nằm ở đâu so với bộ lọc: từng cái riêng lẻ không quan trọng lắm nhưng tổng hợp lại thì rất quan trọng, vì người dùng xây dựng một mô hình tinh thần về không gian của sản phẩm qua nhiều lần sử dụng, và mỗi lần placement không nhất quán buộc họ phải học lại từ đầu.
- Thay đổi placement theo responsive — guidance cần nói rõ điều gì xảy ra với placement ở màn hình hẹp hơn (một toolbar căn phải sụp xuống thành overflow menu dưới một breakpoint, một form hai cột xếp thành một cột), thay vì để tùy từng team tự phán đoán.
Nguyên tắc chung đáng nêu trong tài liệu của mọi design system: placement không phải là chuyện thẩm mỹ phụ thêm, nó là một phần trong hợp đồng của component với người dùng, ngang hàng với màu sắc và label của nó.
Do/don’t guidance: mẫu hình ảnh song song
Mẫu tài liệu dễ nhận ra nhất trong các design system trưởng thành là cặp do/don’t: một ví dụ đúng được đặt song song với một ví dụ sai, mỗi cái được chú thích bằng một lý do ngắn gọn, cụ thể. Mẫu này được dùng nhất quán đến mức — Atlassian, Shopify Polaris, Carbon, Material Design, và guidance của chính IBM đều độc lập hội tụ về nó — vì nó hiệu quả với những lý do mà văn bản thuần túy không có được:
- Nó cho thấy thay vì chỉ nói. Một câu như “đừng nhồi nhiều câu vào label của button” là trừu tượng; một screenshot của một button cố gắng chứa hai câu văn thì sai một cách rõ ràng, trực quan mà văn xuôi không làm được.
- Có thể review chỉ bằng một cái liếc mắt. Một designer hay engineer đang lướt tài liệu trước deadline có thể nhận ra bản nháp của chính mình trong cột “don’t” mà không cần đọc từng chữ.
- Nó mã hóa lý do, không chỉ quy tắc. Những caption do/don’t tốt nhất không chỉ nói “đừng làm thế này” — chúng nói tại sao (“bị cắt cụt đến mức mất nghĩa,” “tạo ra thứ tự focus mơ hồ cho người dùng bàn phím”), giúp người đọc khái quát hóa quy tắc sang những tình huống mà ví dụ không bao quát.
Một mục do/don’t hoàn chỉnh có ba phần: ví dụ trực quan (hoặc code), một dòng caption nêu điều gì đúng hoặc sai, và — quan trọng nhất — lý do bên dưới, chính là thứ thực sự dạy người dùng phán đoán có thể áp dụng rộng thay vì chỉ nhận diện mẫu một cách máy móc. Một số ví dụ cụ thể về những gì nên có trong mỗi cột:
| Component | Do | Don’t (kèm lý do) |
|---|---|---|
| Button | Một action chính, rõ ràng cho mỗi view, gắn nhãn bằng động từ (“Save changes”) | Hai button có trọng lượng thị giác ngang nhau cạnh tranh sự chú ý chính — buộc người dùng phải đoán action nào quan trọng hơn |
| Form field | Label luôn hiển thị phía trên field, kể cả sau khi người dùng bắt đầu gõ | Chỉ dùng placeholder text làm label duy nhất — biến mất ngay khi người dùng gõ, khiến họ mất ngữ cảnh nếu nhìn đi chỗ khác rồi quay lại |
| Modal | Tiêu đề nêu rõ tác vụ (“Delete this project?”) | Tiêu đề dùng chung chung (“Confirm”) — không cho người dùng biết họ đang xác nhận điều gì nếu không đọc phần body |
| Banner | Một banner cho một mối quan tâm, có thể dismiss độc lập | Xếp chồng nhiều banner mức độ nghiêm trọng khác nhau cùng lúc — cái khẩn cấp bị chìm giữa những cái thường lệ |
Tài liệu do/don’t nên nằm ngay trên trang catalog của component, cạnh guidance mà nó minh họa — không phải trong một phụ lục “best practices” riêng biệt, dễ bị bỏ sót — vì toàn bộ giá trị của nó là được nhìn thấy đúng lúc ai đó đang quyết định cách dùng component.
Khái niệm chính
Tài liệu hóa sizes và visual states
Ngoài “khi nào” và “ở đâu,” consumer cần biết component có thể trông như thế nào — toàn bộ bề mặt variant của nó — để họ dùng một variant có sẵn thay vì tự tạo variant mới. Điều này có hai chiều liên quan nhưng khác nhau:
Sizes. Hầu hết các component xuất hiện trong nhiều ngữ cảnh mật độ khác nhau (một hàng trong table so với một form toàn trang so với một toolbar gọn) được ship với một số lượng nhỏ size đã được tài liệu hóa — thường là small/medium/large, hoặc một thang số. Tài liệu size tốt không chỉ nói các size trông như thế nào mà còn khi nào áp dụng cái nào:
| Size | Trường hợp dùng điển hình |
|---|---|
| Small | Ngữ cảnh dày đặc: data table, toolbar, filter bar gọn |
| Medium (mặc định) | Hầu hết form và nội dung trang thông thường |
| Large | Trang marketing, hero section, hoặc call-to-action chính cần trọng lượng thị giác |
Thiếu bảng này, engineer có xu hướng mặc định dùng size nào họ vừa thấy dùng gần đây nhất, thay vì size phù hợp với ngữ cảnh mật độ của họ, đó là cách việc dùng size không nhất quán len lỏi vào sản phẩm theo thời gian.
States. Mỗi component tương tác có một vòng đời đầy đủ các visual state ngoài hình dáng mặc định, và tài liệu phải thể hiện tất cả, không chỉ “happy path” mặc định:
| State | Nó truyền tải điều gì |
|---|---|
| Default / resting | Hình dáng cơ bản |
| Hover | Sẵn sàng tương tác, con trỏ đang ở trên nó |
| Focus (bàn phím) | Đang được nhắm đến bởi điều hướng bàn phím — phải rõ ràng khác biệt về thị giác để đảm bảo accessibility |
| Active / pressed | Đang được click hoặc chạm |
| Disabled | Hiện không tương tác được, với lý do được ngầm hiểu từ ngữ cảnh |
| Loading | Một hành động bất đồng bộ do component này kích hoạt đang diễn ra |
| Error / invalid | Input hoặc state không đạt validation |
| Selected / checked | Áp dụng cho toggle, checkbox, tab — chỉ ra lựa chọn hiện tại |
| Empty | Component chưa có nội dung (ví dụ một Select rỗng chưa load option nào) |
Một trang catalog component chỉ thể hiện state mặc định thì đang tài liệu hóa khoảng một phần mười bề mặt thực tế của component; các state ở trên chính là nơi các bản triển khai không nhất quán, chưa hoàn thiện phân kỳ giữa các team, và cũng chính là nơi các regression về accessibility (một focus ring vô hình, một disabled state không phân biệt được với error state) thường ẩn náu. Xem ./04-core-components-inputs-and-actions.md để biết các component input và action mà ma trận state đầy đủ quan trọng nhất (button, form field, toggle), và ./05-core-components-content-and-feedback.md cho các component feedback (banner, toast, alert) mà state của chúng truyền tải mức độ nghiêm trọng và cấp bách hơn là tính tương tác.
Tài liệu pattern so với tài liệu component
Một component được tài liệu hóa như một đơn vị tự thân: prop, state, hợp đồng accessibility của nó. Một pattern khác biệt về bản chất, không chỉ về quy mô — nó là một công thức được tài liệu hóa để kết hợp nhiều component nhằm giải quyết một vấn đề tái diễn ở cấp cao hơn, và vì nó mang tính composition, nó cần một hình dạng tài liệu hoàn toàn khác.
Một số ví dụ phổ biến về pattern (khác với các component bên trong nó):
- Empty state pattern — kết hợp một illustration/icon, một tiêu đề, phần text giải thích, và một button call-to-action chính, được sắp xếp theo một layout cụ thể, dùng bất cứ khi nào một list, table, hoặc dashboard chưa có dữ liệu. Tài liệu của pattern này phải bao quát những điều mà không component đơn lẻ nào trong nó có thể bao quát: tiêu đề nên mang tông giọng gì (khích lệ, không phải xin lỗi), CTA có bắt buộc hay không, và pattern thích ứng như thế nào khi empty state là do bộ lọc (tạm thời) so với thực sự không có dữ liệu (vĩnh viễn).
- Confirmation pattern — kết hợp một
Modal, một tiêu đề, phần body copy nêu rõ hậu quả, và một cặp button (action mang tính phá hủy + cancel), với quy tắc cụ thể về vị trí button và button nào nổi bật hơn về thị giác. Tài liệu pattern ở đây phải nêu cả quy tắc nội dung (nêu rõ hậu quả, không chỉ “Bạn có chắc không?”) lẫn quy tắc composition (component nào, theo thứ tự nào). - Form validation pattern — kết hợp các error state cấp field, thông báo lỗi cấp field, và thường thêm một banner tóm tắt cấp trang liệt kê tất cả lỗi, với quy tắc về khi nào mỗi lớp xuất hiện (inline khi đang gõ so với khi submit) và focus di chuyển đến lỗi đầu tiên như thế nào.
- Data table with filters pattern — kết hợp một table component, các filter control, số lượng kết quả, phân trang, và một empty state (cho trường hợp không có kết quả sau khi lọc), với quy tắc về cách các phần này đồng bộ với nhau.
Sự khác biệt này có những hệ quả thực tế cho tài liệu:
| Khía cạnh | Tài liệu component | Tài liệu pattern |
|---|---|---|
| Đơn vị tài liệu | Một component đơn lẻ và API của nó | Một công thức có tên kết hợp nhiều component |
| Nó chỉ định điều gì | Prop, state, hợp đồng a11y, ma trận size/variant | Kết hợp component nào, theo thứ tự/layout nào, và các quy tắc nội dung gắn kết chúng lại |
| Reuse xảy ra ở đâu | Import và cấu hình component | Sao chép cấu trúc của công thức; có thể là hoặc không phải một shared code component theo nghĩa đen |
| Failure mode khi thiếu | Dùng sai một component tùy tiện | Mỗi team tự sáng chế phiên bản riêng của cùng một vấn đề UI tái diễn, mỗi cái một kiểu |
| Vị trí điển hình trong catalog | Trang riêng của component | Một mục “Patterns” riêng, thường cross-link đến các component nó kết hợp |
Một design system chỉ tài liệu hóa component mà không bao giờ tài liệu hóa pattern vẫn để các team tự tái phát minh các composition tái diễn một cách độc lập — chính xác là loại công sức trùng lặp, không nhất quán mà một design system được sinh ra để loại bỏ. Pattern là nơi guidance của một design system nâng cấp từ “cái này hoạt động ra sao” lên “làm sao chúng ta giải quyết vấn đề tái diễn này theo cùng một cách mỗi lần,” và chúng xứng đáng có một section tài liệu riêng thay vì bị rải rác trên các trang component đơn lẻ tình cờ được dùng bên trong chúng.
Cấu trúc một trang catalog component tốt
Gộp tất cả những điều trên lại, một trang catalog component trưởng thành không chỉ là một code sample — nó là một tài liệu nhỏ, có cấu trúc, trả lời một tập cố định các câu hỏi mỗi lần, theo cùng một thứ tự, để consumer học được nên tìm ở đâu. Các phần tử sau lặp lại xuyên suốt hầu như mọi trang tài liệu design system được đánh giá cao:
| Phần tử trang catalog | Nội dung |
|---|---|
| Live, interactive preview | Một instance đang chạy, được render của component, thường có control để bật/tắt prop/variant trực tiếp |
| Code snippet | Code sử dụng có thể copy-paste trong (các) framework mà hệ thống hỗ trợ |
| Usage guidance | Quy tắc “khi nào dùng cái này thay vì cái khác,” phát biểu như một heuristic cụ thể |
| Placement guidance | Component thường nằm ở đâu trong layout, kèm ghi chú responsive nếu có |
| Ví dụ do/don’t | Ví dụ đúng/sai song song, có nêu lý do |
| Ma trận size và state | Mọi size và mọi visual state đã được tài liệu hóa, thể hiện tường minh |
| Bảng prop / API | Mọi prop, kiểu dữ liệu, giá trị mặc định, và mô tả ngắn |
| Ghi chú accessibility | Tương tác bàn phím, ARIA role/attribute, đảm bảo về color-contrast, hành vi screen-reader |
| Content guidance | Quy tắc về giọng điệu/tone và độ dài copy cho bất kỳ text nào component hiển thị (label, placeholder text, error message) |
| Related components | Link đến các phương án thay thế và các component thường được dùng kèm với component này |
| Changelog / lịch sử phiên bản | Điều gì đã thay đổi giữa các version, đặc biệt là breaking change |
Mỗi phần tử trên tồn tại để trả lời một câu hỏi cụ thể mà consumer có tại một thời điểm cụ thể, đó là lý do vì sao bỏ sót bất kỳ cái nào trong số đó sẽ tái tạo lại một trong những failure mode đã nêu ở phần Tổng quan — thiếu bảng prop nghĩa là engineer phải đọc source code để biết cái gì có thể cấu hình; thiếu phần accessibility nghĩa là hành vi bàn phím và screen-reader sẽ được phát hiện (hoặc bị bỏ sót) ở production thay vì được tài liệu hóa từ trước.
Best Practices
Viết guidance như một quy tắc quyết định, không phải một mô tả
Chủ đề lặp lại xuyên suốt usage guidance, placement guidance, và caption do/don’t là câu hữu ích nhất là câu mà một người có thể đối chiếu với chính màn hình của họ, không phải câu chỉ mô tả component. “Dùng Select cho nhiều option” là một mô tả; “dùng Select khi có hơn khoảng 5 option và người dùng nhận diện thay vì so sánh” là một quy tắc quyết định với một ngưỡng có thể kiểm chứng. Bất cứ khi nào viết hoặc review tài liệu component, hãy ưu tiên hình thức thứ hai — đó chính là thứ thực sự ngăn chặn được việc dùng sai mà tài liệu tồn tại để phát hiện.
Đặt guidance ngay cạnh thứ nó chi phối
Ví dụ do/don’t, quy tắc usage, và ghi chú placement nên nằm ngay trên trang catalog của chính component đó, không phải trong một file PDF “guidelines” riêng biệt hay một trang wiki mà một engineer bận rộn sẽ không nghĩ đến việc mở ra giữa lúc làm việc. Tài liệu không được gặp đúng lúc quyết định thì cũng như không tồn tại; việc đặt cạnh live preview và code snippet chính là điều khiến guidance thực sự được đọc.
Giải thích lý do, không chỉ quy tắc
Mỗi do/don’t và mỗi usage rule nên đi kèm một mệnh đề “lý do” ngắn gọn. Quy tắc không có lý do bị xem như sở thích phong cách tùy tiện và là thứ đầu tiên bị bỏ qua khi áp lực deadline; quy tắc có lý do nêu rõ (“bị cắt cụt trên viewport nhỏ hơn,” “phá vỡ thứ tự focus bàn phím”) có thể khái quát hóa sang những tình huống mà ví dụ cụ thể không bao quát, và có nhiều khả năng được tuân thủ hơn hẳn kể cả khi không ai giám sát.
Tài liệu hóa toàn bộ ma trận state và size, không chỉ mặc định
Một component được ship vào catalog chỉ với state mặc định, resting được tài liệu hóa sẽ tích lũy dần những bản triển khai phân kỳ âm thầm của hover, focus, disabled, loading, và error state ở mỗi team dùng nó. Hãy coi ma trận state là một phần của hợp đồng công khai của component, quan trọng ngang với bảng prop của nó, và xứng đáng có một section riêng trên trang catalog. Điều tương tự áp dụng cho size variant: nếu một size tồn tại, nó phải được thể hiện kèm trường hợp sử dụng cụ thể, nếu không nó sẽ không được dùng trong khi engineer tự chế biến thứ riêng của mình.
Tách tài liệu pattern khỏi tài liệu component, và cross-link rộng rãi
Đừng cố nhồi một pattern mang tính composition (empty state, confirmation, form validation) vào trang catalog của một component đơn lẻ — hãy cho pattern một section tài liệu riêng, vì chúng kết hợp nhiều component và mang theo các quy tắc nội dung không thuộc về riêng component nào. Từ đó, cross-link mạnh mẽ theo cả hai chiều: một trang pattern nên link đến mọi component nó kết hợp, và một trang component nên ghi chú những pattern nào thường dùng nó, để consumer bắt đầu từ đầu nào cũng có thể điều hướng sang đầu kia.
Coi tài liệu là một deliverable hạng nhất, được versioning của component, không phải một việc làm thêm sau
Một component chưa “xong” khi code của nó được merge; nó xong khi trang catalog của nó có usage guidance, placement guidance, ví dụ do/don’t, ma trận size/state đầy đủ, bảng API, và ghi chú accessibility, tất cả được review với cùng mức độ nghiêm ngặt như chính code. Nhiều team design system thực thi điều này một cách triệt để, bằng cách chặn việc release một component cho đến khi trang tài liệu của nó hoàn chỉnh — coi tài liệu chưa hoàn thiện như một bug đã ship, không phải một việc để làm sau.
Dùng tooling được xây cho living documentation thay vì static docs dễ lỗi thời
Tài liệu tĩnh (một trang wiki, một file PDF, một slide deck) trở nên lỗi thời ngay khi code của component thay đổi bên dưới nó, vì không có gì buộc hai thứ này phải đồng bộ với nhau. Storybook đã trở thành chuẩn mực thực tế cho tài liệu component chính vì nó render tài liệu từ code thực tế của component — story là những instance chạy được thực sự của component, và hệ sinh thái addon của nó (Controls, Docs, Accessibility) tự động sinh ra bảng prop, live preview tương tác, và thậm chí cả kiểm tra a11y tự động ngay từ cùng nguồn được ship lên production. Điều này được trình bày sâu hơn trong ./09-tooling-and-design-to-dev-workflow.md; điểm đáng ghi nhớ ở đây là mẫu tài liệu (một live preview + một bảng prop + state được thể hiện tường minh) dễ giữ đúng sự thật hơn nhiều khi tooling sinh ra nó từ source code, thay vì khi ai đó tự viết tay và tự bảo trì riêng biệt.
Bảng: phần tử tài liệu → câu hỏi nó trả lời
| Phần tử tài liệu | Câu hỏi nó trả lời cho consumer |
|---|---|
| Usage guidance | ”Tôi nên dùng component này, hay một cái khác?” |
| Placement guidance | ”Nó nằm ở đâu trên màn hình này?” |
| Ví dụ do/don’t | ”Cách tôi đang dùng nó có đúng không?” |
| Ma trận size | ”Size nào phù hợp với ngữ cảnh này?” |
| Ma trận state | ”Nó trông như thế nào trong mọi tình huống có thể xảy ra?” |
| Bảng prop / API | ”Làm sao để cấu hình nó trong code?” |
| Ghi chú accessibility | ”Nó có hoạt động cho người dùng bàn phím và screen-reader không, và tôi còn cần tự kết nối thêm gì?” |
| Content guidance | ”Text bên trong nó nên nói gì, và dài bao nhiêu thì được?” |
| Tài liệu pattern | ”Làm sao kết hợp nhiều component để giải quyết đúng vấn đề tái diễn này?” |
| Related components | ”Có thứ gì phù hợp hơn với trường hợp cụ thể của tôi không?” |
Bảng này tự nó là một công cụ audit hữu ích: với bất kỳ component nào trong catalog, đối chiếu từng dòng với trang tài liệu thực tế của nó sẽ nhanh chóng lộ ra những câu hỏi nào consumer phải tự trả lời — và những khoảng trống đó chính là nơi việc dùng sai và tái phát minh len lỏi vào một cách đáng tin cậy. Xem ./10-content-design-and-writing-guidelines.md để hiểu sâu hơn về dòng content guidance, vì quy tắc về copy và tone là một chủ đề đủ lớn để có riêng một note.
Tài liệu tham khảo
- Storybook — Documentation — tài liệu component tự sinh, addon Controls và Docs
- Atlassian Design System — Content guidelines — cách Atlassian gắn usage và content guidance với component
- Atlassian Design System — Components — ví dụ thực tế về usage guidance, ví dụ do/don’t, và bảng API trên trang catalog
- Shopify Polaris — Component guidelines — mẫu do/don’t và usage guidance ở quy mô lớn cho developer bên thứ ba
- Carbon Design System — Components — quy ước tài liệu hóa state và accessibility
- Material Design — Components — usage guidance gắn với triết lý thiết kế (elevation, motion)
- Nielsen Norman Group — Design Systems 101 — lý giải dựa trên nghiên cứu về vì sao tài liệu quyết định mức độ adoption
Part of the Design System Roadmap knowledge base.
Overview
A component is only as useful as the guidance that surrounds it. Ship a beautifully engineered Select component with clean props, solid accessibility, and zero written guidance, and two things happen within a quarter: some teams misuse it (a Select crammed with 40 unsorted options, or a form using three different input patterns for the same kind of choice), and other teams route around it entirely, reimplementing a near-identical dropdown from scratch because they didn’t know the shared one existed or didn’t trust it to do what they needed. Both outcomes are silent failures — nobody files a bug, the code still compiles, the screen still renders — but they are exactly the failures a design system exists to prevent. This is why documentation is not a “nice to have” bolted onto a component after the fact; it is the mechanism through which a design system actually delivers its value. The component is the artifact; the documentation is what transfers the decision-making that produced it to every future consumer who wasn’t in the room.
This note is about the second, less-glamorous half of building a design system component: not “how do we build a good Select,” but “how do we teach two hundred engineers and designers who will never talk to us directly to use it well, and to trust it enough to reach for it before writing their own.” That teaching happens through a specific set of documentation patterns — usage guidance, placement guidance, do/don’t examples, size and state references, and pattern-level documentation for compositions — each answering a different question a consumer has at the moment they’re about to make a UI decision.
The cost of missing guidance
| Missing guidance | What happens in practice |
|---|---|
| No usage guidance (“when do I use this vs. the alternative?”) | Teams guess, and guess inconsistently — one screen uses a Select for 3 options, another uses radio buttons for 12 |
| No placement guidance (“where does this go on the page?”) | Primary actions end up in different corners of every form; banners appear inline on one page and pinned to the top on another |
| No do/don’t examples | Subtle misuse (truncated labels, wrong hierarchy of button emphasis) ships to production because nothing visually flagged it as wrong |
| No size/state documentation | Engineers invent ad hoc variants (“just add a tiny prop”) because they don’t know a suitable size already exists |
| No pattern documentation | Every team builds its own empty state, its own confirmation dialog, from raw components, each slightly different and each re-solving problems (focus management, copy tone) that were already solved once |
Every row above describes reinvention or inconsistency that costs real engineering time and erodes the product’s coherence — and every row is preventable with documentation that answers the specific question a consumer is asking at the point of use.
Fundamentals
Usage guidance: when to use this component vs. an alternative
The single most valuable sentence in any component’s documentation is the one that tells a consumer when to reach for it — and, just as important, when not to, pointing them at the right alternative instead. Components rarely exist in isolation; they exist in small families of components that solve related problems with different tradeoffs (a Select vs. a radio group vs. a combobox, a Modal vs. an inline Banner, a Tabs component vs. an Accordion). Without an explicit decision rule, engineers default to whichever component they used last or happen to remember, regardless of fit.
A good usage-guidance section states the rule as a concrete, testable heuristic rather than vague advice like “use this when appropriate.” Some real examples of the pattern:
| Component | Good usage rule | Why it works |
|---|---|---|
Select (dropdown) | Use when there are more than ~5 options and the user already knows what they want (recognition, not comparison) | Gives a numeric threshold and a cognitive reason, not just a preference |
| Radio buttons | Use when there are 2–5 options and the user needs to compare them side by side before choosing | Directly contrasts with the Select rule above so the two components don’t compete ambiguously |
| Checkbox | Use for a single independent on/off choice, or a small set of independent multi-select options | Distinguishes from radio buttons (mutually exclusive) and toggle switches (immediate effect) |
| Toggle switch | Use when the change takes effect immediately, with no separate “Save” step | The defining difference from a checkbox inside a form is immediacy of effect, not visual style |
Modal | Use for a task that must interrupt the current flow and be resolved before the user continues (confirmation, a short focused task) | Ties the component to an interaction cost (it blocks everything else) so teams don’t reach for it out of habit |
Inline Banner | Use for contextual, non-blocking information tied to the content on the page | Contrasts directly with Modal on the same axis: blocking vs. non-blocking |
Tabs | Use when a user needs to switch between a small number (≤ 6–7) of related, parallel views of similar importance | Calls out the failure mode: too many tabs, or tabs used for a linear step-by-step flow (which should be a stepper instead) |
Notice the pattern across every row: the rule references a threshold (number of options, number of tabs), a behavior (immediate vs. deferred effect, blocking vs. non-blocking), or a user intent (recognition vs. comparison) — something a reviewer can actually check a screen against, rather than a subjective judgment call. This is what separates genuinely useful usage guidance from a paragraph nobody reads.
Placement guidance: where a component belongs in a layout
A second, distinct kind of guidance answers not “which component” but “where on the screen.” The same button, banner, or field behaves and reads completely differently depending on its position, and design systems that skip placement guidance end up with components that are individually correct but collectively inconsistent — every form has its primary action in a different spot, every alert shows up in a different corner.
Placement guidance typically covers:
- Hierarchy and emphasis by position — in most reading directions (left-to-right, top-to-bottom), a primary action sits bottom-right of a form or bottom of a modal footer (the natural end point of the reading flow), with secondary/tertiary actions to its left, in decreasing visual weight. Reversing this — putting the destructive or secondary action in the visually dominant position — is a common, costly mistake that a placement rule prevents.
- Page-level vs. inline scope — a system
Bannerused for a page-wide, must-see message (an outage notice, a global warning) belongs pinned at the very top of the page, above all content; the same visual component used to flag a problem with one specific field or section belongs directly adjacent to that section, inline, not at the page top, because placement communicates scope. Mixing these up misleads users about how far the message’s relevance extends. - Repeated-element consistency — where a “Cancel” link sits relative to a “Save” button, where breadcrumbs sit relative to a page title, where a search field sits relative to filters: these are low-stakes individually but high-stakes in aggregate, because a user builds a spatial mental model of the product over repeated use, and every inconsistent placement forces them to re-learn it.
- Responsive placement changes — guidance should say explicitly what happens to placement at narrower widths (a right-aligned toolbar that collapses into an overflow menu below a breakpoint, a two-column form that stacks to one column) rather than leaving it to per-team judgment.
The general principle worth stating in every design system’s documentation: placement is not a visual-design afterthought, it is part of the component’s contract with the user, on par with its color and label.
Do/don’t guidance: the paired visual pattern
The most immediately recognizable documentation pattern in mature design systems is the do/don’t pair: a correct example shown side by side with an incorrect one, each annotated with a short, specific reason. This pattern is so consistently used — Atlassian, Shopify Polaris, Carbon, Material Design, and IBM’s own guidance all converge on it independently — because it works for reasons plain text alone doesn’t:
- It shows rather than tells. A sentence like “don’t overload a button label with multiple sentences” is abstract; a screenshot of a button trying to hold two sentences of text is immediately, viscerally wrong in a way prose isn’t.
- It’s reviewable at a glance. A designer or engineer scanning documentation before a deadline can recognize their own draft in the “don’t” column without reading every word.
- It encodes the reason, not just the rule. The best do/don’t captions don’t just say “don’t do this” — they say why (“truncated to the point of losing meaning,” “creates ambiguous focus order for keyboard users”), which lets people generalize the rule to situations the example didn’t cover.
A well-formed do/don’t entry has three parts: the visual (or code) example, a one-line caption stating what’s right or wrong, and — critically — the underlying reason, which is what actually teaches transferable judgment rather than rote pattern-matching. Some concrete examples of what belongs in each column:
| Component | Do | Don’t (with reason) |
|---|---|---|
| Button | One clear, primary action per view, labeled with a verb (“Save changes”) | Two buttons of equal visual weight competing for primary attention — forces the user to guess which action matters more |
| Form field | Label always visible above the field, even after the user starts typing | Placeholder text used as the only label — disappears once the user types, so they lose context if they look away and come back |
| Modal | Title states the task plainly (“Delete this project?”) | Title reused as generic chrome (“Confirm”) — doesn’t tell the user what they’re actually confirming without reading the body |
| Banner | One banner per concern, dismissed independently | Stacking multiple banners of different severities at once — the urgent one gets lost among the routine ones |
Do/don’t documentation should live directly on the component’s catalog page, next to the guidance it illustrates — not in a separate “best practices” appendix that’s easy to miss — because its whole value is being seen at the exact moment someone is deciding how to use the component.
Key Concepts
Documenting sizes and visual states
Beyond “when” and “where,” consumers need to know what a component can look like — its full variant surface — so they reach for an existing variant instead of inventing a new one. This has two related but distinct dimensions:
Sizes. Most components that appear in more than one density context (a table row vs. a full-page form vs. a compact toolbar) ship in a small number of documented sizes — commonly small/medium/large, or a numeric scale. Good size documentation states not just what the sizes look like but when each applies:
| Size | Typical use case |
|---|---|
| Small | Dense contexts: data tables, toolbars, compact filter bars |
| Medium (default) | Most forms and general page content |
| Large | Marketing pages, hero sections, or primary calls to action needing visual weight |
Without this table, engineers tend to default to whichever size they’ve seen used most recently, rather than the size that fits their density context, which is how inconsistent size usage creeps into a product over time.
States. Every interactive component has a full lifecycle of visual states beyond its default appearance, and documentation must show all of them, not just the “happy path” default:
| State | What it communicates |
|---|---|
| Default / resting | Baseline appearance |
| Hover | Available for interaction, cursor is over it |
| Focus (keyboard) | Currently targeted by keyboard navigation — must be visually distinct for accessibility |
| Active / pressed | Currently being clicked or tapped |
| Disabled | Not currently interactive, with a reason implied by context |
| Loading | An async action triggered by this component is in flight |
| Error / invalid | Input or state fails validation |
| Selected / checked | Applicable to toggles, checkboxes, tabs — indicates current selection |
| Empty | The component has no content yet (e.g., an empty Select with no options loaded) |
A component catalog page that shows only the default state is documenting roughly a tenth of the component’s actual surface area; the states above are exactly where inconsistent, half-finished implementations diverge across teams, and exactly where accessibility regressions (an invisible focus ring, a disabled state indistinguishable from an error state) tend to hide. See ./04-core-components-inputs-and-actions.md for the input and action components whose full state matrices matter most (buttons, form fields, toggles), and ./05-core-components-content-and-feedback.md for feedback components (banners, toasts, alerts) whose states communicate severity and urgency rather than interactivity.
Pattern documentation vs. component documentation
A component is documented as a self-contained unit: its props, its states, its accessibility contract. A pattern is different in kind, not just in scale — it’s a documented recipe for combining multiple components to solve a recurring, higher-level problem, and because it’s compositional, it needs a different documentation shape entirely.
Common examples of patterns (as distinct from the components inside them):
- Empty state pattern — combines an illustration/icon, a heading, explanatory body text, and a primary call-to-action button, arranged in a specific layout, used whenever a list, table, or dashboard has no data yet. The pattern’s documentation must cover things no single component in it can: what tone the heading should take (encouraging, not apologetic), whether the CTA is required or optional, and how the pattern adapts when the empty state is due to a filter (temporary) versus genuinely no data (permanent).
- Confirmation pattern — combines a
Modal, a title, body copy stating the consequence, and a button pair (destructive action + cancel), with a specific rule about button placement and which one is visually dominant. Pattern documentation here must state the content rule (state the consequence, not just “Are you sure?”) alongside the composition rule (which components, in which order). - Form validation pattern — combines field-level error states, a field-level error message, and often a page-level summary banner listing all errors, with rules about when each layer appears (inline as-you-type vs. on submit) and how focus moves to the first error.
- Data table with filters pattern — combines a table component, filter controls, a results count, pagination, and an empty state (for zero filtered results), with rules about how these pieces stay in sync with each other.
The documentation implications of this distinction matter in practice:
| Aspect | Component documentation | Pattern documentation |
|---|---|---|
| Unit of documentation | A single component and its API | A named recipe combining several components |
| What it specifies | Props, states, a11y contract, size/variant matrix | Which components to combine, in what order/layout, and the content rules that tie them together |
| Where reuse happens | Import and configure the component | Copy the recipe’s structure; may or may not be a literal shared code component |
| Failure mode without it | Ad hoc misuse of one component | Every team invents its own version of the same recurring UI problem, each slightly different |
| Typical home in a catalog | Component’s own page | A separate “Patterns” section, often cross-linking the components it composes |
A design system that only documents components and never documents patterns still leaves teams to reinvent recurring compositions independently — which is precisely the kind of duplicated, inconsistent effort a design system is meant to eliminate. Patterns are where a design system’s guidance graduates from “how does this one thing work” to “how do we solve this recurring problem the same way every time,” and they deserve their own documented section rather than being scattered across the individual component pages that happen to be used inside them.
Anatomy of a good component catalog page
Pulling all of the above together, a mature component catalog page is not just a code sample — it’s a small, structured document that answers a fixed set of questions every time, in the same order, so consumers learn where to look. The following elements recur across essentially every well-regarded design system’s documentation site:
| Catalog page element | What it contains |
|---|---|
| Live, interactive preview | A rendered, working instance of the component, often with controls to toggle props/variants live |
| Code snippet | Copy-pasteable usage code in the framework(s) the system supports |
| Usage guidance | The “when to use this vs. an alternative” rule, stated as a concrete heuristic |
| Placement guidance | Where the component typically belongs in a layout, with any responsive notes |
| Do/don’t examples | Paired correct/incorrect visuals with a stated reason |
| Size and state matrix | Every documented size and every visual state, shown explicitly |
| Props / API table | Every prop, its type, default value, and a short description |
| Accessibility notes | Keyboard interaction, ARIA roles/attributes, color-contrast guarantees, screen-reader behavior |
| Content guidance | Voice/tone and copy-length rules for any text the component displays (labels, placeholder text, error messages) |
| Related components | Links to alternatives and components commonly paired with this one |
| Changelog / version history | What changed between versions, especially breaking changes |
Each of these elements exists to answer a specific question a consumer has at a specific moment, which is why omitting any one of them reintroduces one of the failure modes from the Overview section — a missing props table means an engineer has to read source code to know what’s configurable; a missing accessibility section means keyboard and screen-reader behavior gets discovered (or missed) in production rather than documented up front.
Best Practices
Write guidance as a decision rule, not a description
The recurring theme across usage guidance, placement guidance, and do/don’t captions is that the most useful sentence is one a person can check their own screen against, not one that merely describes the component. “Use Select for many options” is a description; “use Select when there are more than ~5 options and the user recognizes rather than compares” is a decision rule with a testable threshold. Whenever writing or reviewing component documentation, prefer the latter form — it is what actually prevents the misuse the documentation exists to catch.
Keep guidance next to the thing it governs
Do/don’t examples, usage rules, and placement notes should live directly on the component’s own catalog page, not in a separate “guidelines” PDF or wiki page that a busy engineer won’t think to open mid-task. Documentation that isn’t encountered at the point of decision might as well not exist; co-location with the live preview and code snippet is what makes guidance actually get read.
Explain the reason, not just the rule
Every do/don’t and every usage rule should carry a short “why” clause. Rules without reasons get treated as arbitrary style preferences and are the first thing dropped under deadline pressure; rules with a stated reason (“truncates on smaller viewports,” “breaks keyboard focus order”) generalize to situations the specific example didn’t cover, and are far more likely to be respected even when nobody is enforcing them.
Document the full state and size matrix, not just the default
A component that ships to a catalog with only its default, resting state documented will accumulate silently divergent implementations of hover, focus, disabled, loading, and error states across every team that uses it. Treat the state matrix as part of the component’s public contract, equally as important as its props table, and equally deserving of a section on the catalog page. The same applies to size variants: if a size exists, it must be shown with a stated use case, or it will go unused while engineers improvise their own.
Separate pattern documentation from component documentation, and cross-link generously
Don’t try to force a compositional pattern (empty state, confirmation, form validation) into a single component’s catalog page — give patterns their own documented section, since they combine multiple components and carry content rules that don’t belong to any one of them. From there, cross-link aggressively in both directions: a pattern page should link to every component it composes, and a component page should note which patterns commonly use it, so a consumer starting from either end can navigate to the other.
Treat documentation as a first-class, versioned deliverable of the component, not an afterthought
A component is not “done” when its code merges; it’s done when its catalog page has usage guidance, placement guidance, do/don’t examples, a full size/state matrix, an API table, and accessibility notes, all reviewed with the same rigor as the code itself. Many design system teams enforce this literally, by blocking a component’s release until its documentation page is complete — treating incomplete documentation as a shipped bug, not a follow-up task.
Use tooling built for living documentation rather than static docs that drift
Static documentation (a wiki page, a PDF, a slide deck) goes stale the moment the component’s code changes underneath it, because nothing forces the two to stay in sync. Storybook has become the de facto standard for component documentation precisely because it renders documentation from the component’s actual code — stories are literal, runnable instances of the component, and its addon ecosystem (Controls, Docs, Accessibility) auto-generates the props table, the interactive preview, and even automated a11y checks straight from the same source that ships to production. This is covered in depth in ./09-tooling-and-design-to-dev-workflow.md; the point worth internalizing here is that the documentation pattern (a live preview + a props table + states shown explicitly) is much easier to keep truthful when the tooling generates it from source rather than when someone hand-writes and hand-maintains it separately.
Table: documentation element → the question it answers
| Documentation element | Question it answers for the consumer |
|---|---|
| Usage guidance | ”Should I use this component, or a different one?” |
| Placement guidance | ”Where on this screen does it go?” |
| Do/don’t examples | ”Is my specific use of it correct?” |
| Size matrix | ”Which size fits this context?” |
| State matrix | ”What does it look like in every situation it can be in?” |
| Props / API table | ”How do I configure it in code?” |
| Accessibility notes | ”Does it work for keyboard and screen-reader users, and what do I still need to wire up myself?” |
| Content guidance | ”What should the text inside it say, and how long can it be?” |
| Pattern documentation | ”How do I combine several components to solve this recurring problem correctly?” |
| Related components | ”Is there something better suited to my specific case?” |
This table is a useful audit tool in its own right: for any component in a catalog, checking each row against its actual documentation page quickly reveals which questions a consumer would be left to answer on their own — and those gaps are reliably where misuse and reinvention creep in. See ./10-content-design-and-writing-guidelines.md for the content-guidance row in more depth, since copy and tone rules are a large enough topic to warrant their own dedicated treatment.
References
- Storybook — Documentation — auto-generated component documentation, Controls, and Docs addon
- Atlassian Design System — Content guidelines — Atlassian’s approach to pairing components with usage and content guidance
- Atlassian Design System — Components — example of usage guidance, do/don’t examples, and API tables on real catalog pages
- Shopify Polaris — Component guidelines — do/don’t patterns and usage guidance at scale for third-party developers
- Carbon Design System — Components — state and accessibility documentation conventions
- Material Design — Components — usage guidance tied to design philosophy (elevation, motion)
- Nielsen Norman Group — Design Systems 101 — research-backed rationale for why documentation drives adoption