Content Design & Writing GuidelinesContent Design & Writing Guidelines
Thuộc bộ kiến thức Design System Roadmap.
Tổng quan
Mọi design system đều bỏ khá nhiều công sức để đảm bảo một “primary button” trông giống nhau ở mọi nơi — cùng corner radius, cùng padding, cùng color token. Nhưng rất ít team bỏ công sức tương đương để đảm bảo cái button đó nói cùng một kiểu ở mọi nơi. Màn hình này ghi “Submit,” màn hình khác ghi “Send Request,” màn hình thứ ba ghi “OK, làm luôn!” Một error message ghi “Error: 400 Bad Request,” cái khác ghi “Oops! Có gì đó không ổn 😅,” cái thứ ba thì im lặng không nói gì cả. Không cái nào trong số này là lỗi visual — các button vẫn giống hệt nhau về pixel — nhưng sản phẩm vẫn cho cảm giác được xây bởi năm team khác nhau chưa từng nói chuyện với nhau, bởi vì phần chữ đang mâu thuẫn nhau về việc sản phẩm này thực chất là ai.
Đó chính là lý do vì sao content cần nằm trong design system thay vì để mặc cho ai đang gõ phím lúc đó quyết định: chữ cũng là UI. Người dùng đọc một button label, một error message, hay một empty state trước khi họ để ý đến màu sắc hay đổ bóng của nó, và terminology hoặc tone thiếu nhất quán sẽ bào mòn niềm tin y hệt cách một visual language thiếu nhất quán làm — chỉ là nó âm thầm hơn, vì không ai report bug với nội dung “cái copy này nghe hơi sai sai.” Nhiệm vụ của một design system là biến quyết định đúng thành mặc định và quyết định sai thành việc phải tốn công mới làm được; content xứng đáng có cùng lớp bảo vệ như color hay spacing. Note này sẽ nói về cách viết tài liệu cho chính hệ thống thật tốt, cách viết voice và tone guidelines để nó thực sự thay đổi cách người ta gõ chữ, cách viết microcopy cho button, error message, empty state và placeholder, và content design nằm ở đâu trong design system với tư cách một discipline có contributor riêng — UX writer — bên cạnh visual/interaction designer và engineer.
Kiến thức nền tảng
Vì sao content thuộc về design system
Một design system chỉ ship component mà không có content guidance thì mới giải quyết được một nửa vấn đề consistency, và âm thầm để nửa còn lại quay trở lại. Hãy xem thực tế những gì trôi dạt khi content không có ai sở hữu:
- Terminology trôi dạt. Team này gọi là “workspace,” team kia gọi cùng một khái niệm là “project,” team thứ ba gọi là “org.” Người dùng xây dựng mental model dựa trên thuật ngữ họ thấy đầu tiên, và mỗi lần không nhất quán buộc họ phải kiểm tra lại xem thuật ngữ mới có mang nghĩa khác không.
- Tone trôi dạt. Một confirmation dialog ở phần này của sản phẩm thì nhanh gọn và functional; cùng loại dialog đó ba màn hình sau lại tràn ngập lời lẽ thân mật và dấu chấm than. Đọc liền mạch, sản phẩm cho cảm giác có nhiều nhân cách khác nhau — vì đúng là nó có thật.
- Chất lượng trôi dạt. Không có một chuẩn chung, một số copy được biên tập kỹ càng, số khác thì chỉ là bất cứ thứ gì engineer gõ vội khi nối API response — thường là literally raw error string từ backend, hiện thẳng ra cho người dùng vốn không hề biết
NullPointerExceptionlà gì.
Không có lỗi nào trong số này lộ ra khi làm visual QA. Một màn hình có thể pixel-perfect so với Figma spec mà vẫn “trượt” ngay khi người dùng đọc nó. Đây là lý do vì sao các design system trưởng thành (Atlassian, Shopify Polaris, IBM Carbon, GOV.UK Design System) đều có riêng section content guidelines hoặc voice and tone với mức độ quan trọng ngang với component spec — không phải một phụ lục cho có, mà là một discipline ngang hàng mà contributor được kỳ vọng kiểm tra trước khi ship copy, giống hệt cách họ kiểm tra spacing token trước khi ship margin.
Hệ quả thực tế: content guidelines cần nằm trong cùng hệ thống, với cùng governance, versioning, và review process như component (xem Xây dựng Design System và mô hình stakeholder của nó, cùng Guideline Component & Mẫu tài liệu về cách tài liệu component được cấu trúc — content guidelines đi theo cùng kỷ luật đó, chỉ khác là cho chữ thay vì props).
Viết tài liệu của chính hệ thống cho tốt
Trước khi một design system có thể hướng dẫn contributor viết copy tốt, tài liệu của chính nó phải làm gương cho chuẩn đó — một trang content guidelines đầy văn phong mơ hồ, nặng jargon sẽ tự phá hoại lời khuyên của chính mình. Có vài đặc điểm phân biệt tài liệu thực sự được dùng với tài liệu chỉ được lướt qua một lần rồi bỏ quên:
- Heading theo task, không theo topic. Một heading như “Buttons” buộc người đọc phải tìm cả section mới ra thứ họ cần. Một heading như “Viết button label” hay “Khi nào dùng confirmation dialog thay vì toast” trả lời đúng câu hỏi người đọc thật sự đang có, mà hầu như luôn là “tôi phải làm gì ngay bây giờ, trong tình huống cụ thể này?”
- Đi thẳng vào câu trả lời, không lý thuyết dông dài. Nêu câu trả lời “khi nào dùng cái này” ngay trong một, hai câu đầu, rồi mới giải thích lý do. Người đọc đang phân vân giữa error banner và toast notification nên đọc được “Dùng banner khi lỗi chặn người dùng không làm tiếp được; dùng toast khi không chặn” ngay câu mở đầu — lý do và edge case có thể theo sau, nhưng quyết định không nên bị chôn dưới ba đoạn văn bối cảnh.
- Ví dụ chạy được thật, không phải Lorem Ipsum giả. Một code example hiện
<Button label="Click here" />chẳng dạy được gì về microcopy tốt; nó nên hiện<Button label="Save changes" />và, lý tưởng nhất, một phương án bị từ chối đặt cạnh bên. Logic này áp dụng cả ngoài code snippet, vào ví dụ voice/tone: một “don’t” được tài liệu hóa nên là một câu thực tế mà contributor có thể thật sự gõ, không phải một strawman chẳng ai viết. - Dễ tra cứu và dễ quét. Những đoạn văn dài liên tục chôn vùi cái rule cụ thể ai đó đang tìm. Section ngắn, heading rõ ràng, và bảng cho bất cứ thứ gì có hơn ba dòng so sánh (ví dụ tone, pattern error message, terminology) giúp contributor quét đến đúng dòng cần thay vì đọc từ đầu đến cuối mỗi lần.
- Đặt gần nơi được dùng. Guidance chỉ nằm trong wiki mà không ai nhớ để kiểm tra sẽ bị bỏ qua; guidance hiện ngay trong trang tài liệu của chính component (ví dụ một tab “Writing guidelines” nằm ngay cạnh tab “Props” trong docs của Button component) sẽ được đọc đúng lúc cần.
Khái niệm chính
Voice và tone
Sự phân biệt hữu ích nhất trong content design là giữa voice và tone, vì nhầm lẫn hai khái niệm này là lý do phổ biến nhất khiến team hoặc chuẩn hóa quá mức (mọi message nghe robotic và giống hệt nhau) hoặc chuẩn hóa chưa đủ (mọi message nghe như thuộc về sản phẩm khác nhau).
Voice là tính cách nhất quán của sản phẩm — nó không đổi theo bối cảnh, giống như tính cách cốt lõi của một con người không đổi tùy vào việc họ đang nói chuyện với ai. Sản phẩm này formal hay casual? Trực tiếp hay giải thích nhiều? Tự tin hay khiêm nhường? Voice của sản phẩm được quyết định một lần (lý tưởng nhất là cùng lúc với việc xác định brand values và design principles — xem Design Language & Nguyên tắc thiết kế) rồi áp dụng ở mọi nơi.
Tone là voice được điều chỉnh theo bối cảnh. Cùng một sản phẩm, cùng tính cách nền tảng, nhưng nghe khác đi khi ăn mừng một thành công so với khi báo một thất bại — không phải vì nó có nhiều tính cách khác nhau, mà vì một người giao tiếp giỏi tự nhiên điều chỉnh cách truyền đạt theo tình huống và trạng thái cảm xúc của người đọc lúc đó. Một error message và một success message chia sẻ chung voice của sản phẩm (chẳng hạn “rõ ràng và thẳng thắn”) nhưng dùng tone khác nhau: success message có thể ấm áp và ngắn gọn, còn error message cần bình tĩnh hơn, cẩn trọng hơn và cung cấp thông tin nhiều hơn vì người đọc lúc đó nhiều khả năng đang bực bội hoặc lo lắng.
| Khía cạnh | Voice | Tone |
|---|---|---|
| Có đổi theo bối cảnh không? | Không — hằng định xuyên suốt sản phẩm | Có — điều chỉnh theo tình huống |
| Phép ẩn dụ | Tính cách cốt lõi của một người | Cách người đó điều chỉnh cách nói: an ủi bạn bè khác với báo cáo công việc |
| Ví dụ | ”Chúng ta viết như một người bạn am hiểu, không phải như phòng pháp lý” | Cũng người bạn đó nghe khích lệ ở empty state, xin lỗi và chính xác ở error, ăn mừng nhưng ngắn gọn ở success toast |
| Được định nghĩa ở đâu | Brand/content strategy, cùng lúc với design principles | Guidance theo từng bối cảnh: error message, success state, onboarding, destructive action |
| Governance | Hiếm khi thay đổi | Được review và mở rộng khi có context/component mới |
Một bài test hữu ích để xem team có thực sự có voice và tone riêng biệt hay không (thay vì chỉ có một hướng dẫn chung chung “hãy tử tế”): đọc to ba đoạn copy từ ba bối cảnh rất khác nhau — một error message, một empty state marketing, và một thông báo billing/legal. Nếu chúng nghe như cùng một người viết đang điều chỉnh theo bối cảnh, voice và tone đều đang hoạt động tốt. Nếu chúng nghe có thể thay thế cho nhau với copy của đối thủ, hoặc như ba người viết chẳng liên quan gì đến nhau, hệ thống cần định nghĩa rõ ràng hơn cho một hoặc cả hai.
Hướng dẫn microcopy
Microcopy là phần chữ nhỏ, tần suất xuất hiện cao, mang trong mình một tỷ trọng bất cân xứng của chất lượng cảm nhận sản phẩm, vì nó xuất hiện liên tục và đúng vào những lúc người dùng đang cố hoàn thành một việc cụ thể: button label, error message, empty state, và placeholder text. Mỗi loại có failure mode riêng và quy tắc ngón tay cái riêng.
Button label: verb + noun, nói rõ hành động cụ thể. Một label nên cho người dùng biết chính xác điều gì sẽ xảy ra khi họ bấm, chứ không chỉ là có gì đó sẽ xảy ra. “Submit” và “OK” đủ mơ hồ để buộc người dùng phải đọc lại ngữ cảnh xung quanh mới nhớ ra họ đang đồng ý với cái gì; “Save changes,” “Delete project,” và “Send invite” thì rõ ràng không cần ngữ cảnh, và điều đó quan trọng nhất đúng vào những lúc (destructive action, irreversible action) mà sự mơ hồ tốn kém nhất.
Error message: điều gì đã xảy ra, tại sao, và tiếp theo phải làm gì. Một error message tốt có ba nhiệm vụ, và bỏ sót bất kỳ cái nào cũng khiến người dùng bị mắc kẹt. Nó nói rõ điều gì đã xảy ra bằng ngôn ngữ dễ hiểu (không phải raw system error), cho biết tại sao khi lý do hữu ích và có thể biết được (không phải “đã xảy ra lỗi” mà không có thêm thông tin gì), và — quan trọng nhất — nói cho người dùng biết tiếp theo phải làm gì. Một message chỉ báo lỗi mà không có bước tiếp theo biến người dùng thành một debugger không công cho sản phẩm. Có hai failure mode đáng nêu tên rõ vì chúng phổ biến và cả hai đều bào mòn niềm tin: đổ lỗi cho người dùng (“Bạn đã nhập giá trị không hợp lệ” trong khi yêu cầu của field chưa từng được hiển thị) nghe như thù địch dù đúng về mặt kỹ thuật, và vui vẻ giả tạo trước một lỗi thật (“Oops! 😅 Có vẻ như có gì đó trục trặc rồi!”) nghe như coi thường một vấn đề có thể vừa khiến người dùng mất công việc hoặc mất dữ liệu.
Empty state: giải thích cái gì đang thiếu và phải làm gì tiếp, đừng chỉ nói “chưa có gì ở đây.” Một empty state là cơ hội để hướng dẫn, không phải một ngõ cụt — nó thường là thứ đầu tiên mà người dùng mới thấy ở một màn hình cụ thể, trước khi họ xây dựng được mental model về việc màn hình đó thường chứa gì. Một câu bare “Không có mục nào” hoặc “Không tìm thấy kết quả” chỉ trả lời được nửa câu hỏi của người dùng (ở đây có gì — không có gì cả) và bỏ mặc nửa còn lại (vậy giờ tôi phải làm gì?).
Placeholder text: một ví dụ về input hợp lệ, không bao giờ là chính cái label. Placeholder nên hiện format hoặc loại câu trả lời được mong đợi (ví dụ “vd: jane@company.com”) và biến mất ngay khi người dùng bắt đầu gõ — nó không thay thế được một label cố định của field, vì placeholder biến mất khi focus có nghĩa là người dùng bị gián đoạn giữa chừng khi điền form sẽ mất đi manh mối duy nhất về việc field đó đang hỏi gì.
Before/after: viết lại microcopy chung chung
Copy chung chung, mặc định của hệ thống thường không hẳn là sai — nó vẫn hoạt động — mà là một cơ hội bị bỏ lỡ: nó không dạy người dùng điều gì và không trấn an họ điều gì cả. Bản viết lại gần như không bao giờ dài hơn; nó chỉ cụ thể hơn.
| Bối cảnh | Before (chung chung) | After (rõ ràng & hữu ích) | Vì sao tốt hơn |
|---|---|---|---|
| Nút lưu | ”Submit" | "Save changes” | Nêu rõ hành động cụ thể và đối tượng của nó; không cần đọc lại form mới biết đang submit cái gì |
| Hành động destructive | ”OK” / “Yes" | "Delete project” | Một hành động không thể hoàn tác không bao giờ nên núp sau một từ xác nhận chung chung |
| Lỗi validation form | ”Invalid input" | "Nhập email hợp lệ, ví dụ jane@company.com” | Nêu rõ cái gì sai và hiện luôn format mong đợi trong một dòng |
| Lỗi mạng | ”Error: 500" | "Chúng tôi chưa lưu được thay đổi của bạn. Kiểm tra kết nối mạng và thử lại.” | Ngôn ngữ dễ hiểu, không đổ lỗi, và có bước tiếp theo cụ thể |
| Kết quả tìm kiếm rỗng | ”Không tìm thấy kết quả" | "Không có kết quả cho “budget report” — thử từ khóa khác hoặc kiểm tra lại filter” | Nhắc lại query để người dùng tin search đã thực sự chạy, và gợi ý hai bước tiếp theo cụ thể |
| Empty state (lần dùng đầu) | “Chưa có gì ở đây" | "Bạn chưa tạo project nào. Tạo project đầu tiên để bắt đầu.” + nút “Create project” | Biến ngõ cụt thành hành động tiếp theo, ngay tại nơi người dùng đang nhìn |
| Trạng thái đang tải/xử lý | ”Vui lòng đợi…" | "Đang tải file lên — có thể mất một phút với video lớn” | Thiết lập kỳ vọng về thời gian chờ để người dùng không nghĩ app bị đứng |
| Placeholder trong field ngày tháng | ”Placeholder text” (nghĩa đen!) | ”MM/DD/YYYY” | Hiện đúng format mong đợi thay vì một chuỗi filler vô nghĩa |
| Xác nhận thành công | ”Success!" | "Đã lưu thay đổi. Đồng nghiệp của bạn sẽ thấy cập nhật này ngay lập tức.” | Xác nhận cả hành động lẫn hệ quả của nó, điều quan trọng khi hiệu ứng không hiển thị ngay trên màn hình |
Tone of voice: khung adjective-pair thực dụng
Một hướng dẫn trừu tượng như “hãy thân thiện” không cho người viết bất cứ điểm tựa nào — thân thiện so với cái gì? Một khung dễ áp dụng hơn ghép mỗi phẩm chất mong muốn với failure mode mà nó đang bảo vệ chống lại, diễn đạt bằng hai tính từ nối với nhau bằng “nhưng không.” Mỗi cặp nên đi kèm ví dụ do/don’t, y hệt một design principle (xem Design Language & Nguyên tắc thiết kế về cùng pattern áp dụng cho visual principles).
| Cặp tính từ | Bảo vệ chống lại điều gì | Do | Don’t |
|---|---|---|---|
| Tự tin, nhưng không kiêu ngạo | Copy nghe như đang khoe khoang hoặc coi thường người dùng | ”Thay đổi của bạn được lưu tự động." | "Đừng lo, chúng tôi lo hết rồi — cứ tin chúng tôi!” |
| Thân thiện, nhưng không lố lăng | Copy tự phá hoại độ tin cậy của chính nó bằng quá nhiều đùa cợt hoặc emoji, nhất là ở những khoảnh khắc nghiêm túc | ”Chúng tôi gặp trục trặc khi lưu file của bạn. Thử lại nhé." | "Ối trời ơi! 🙈 Lỗi của tụi mình!” |
| Rõ ràng, nhưng không cộc lốc | Copy quá ngắn gọn đến mức nghe lạnh lùng hoặc robotic | ”Hành động này không thể hoàn tác. Xóa project?" | "Xóa? Y/N” |
| Hữu ích, nhưng không kẻ cả | Giải thích thừa những gì người dùng đã biết, hoặc nói chuyện bề trên | ”Mật khẩu cần ít nhất 8 ký tự, bao gồm một số." | "Cho bạn biết luôn, hầu hết mọi người quên không thêm số vào mật khẩu, nên đừng để mắc lỗi đó nhé!” |
| Gần gũi, nhưng không thiếu chuyên nghiệp | Ngôn ngữ suồng sã làm giảm niềm tin ở bối cảnh nghiêm túc (billing, legal, security) | “Thẻ của bạn bị từ chối. Thử phương thức thanh toán khác hoặc liên hệ ngân hàng." | "Ui, thẻ bạn bị từ chối rồi haha, thử cái khác đi?” |
| Súc tích, nhưng không mơ hồ | Ngắn gọn bằng cách cắt bớt thông tin người dùng thật sự cần | ”Tải lên file JPG hoặc PNG dưới 5MB." | "Tải lên file hợp lệ.” |
Bài tập cho một team tự viết bảng này là cùng một kỷ luật dùng cho design principles: chọn 4–6 cặp tính từ phản ánh đúng giá trị thực của brand (không phải một danh sách chung chung copy từ guide của công ty khác), và với mỗi cặp, viết một ví dụ “don’t” thực tế — thứ mà một contributor có thiện chí thật sự có thể gõ dưới áp lực deadline — thay vì một strawman phóng đại mà chẳng ai viết. Một “don’t” quá lộ liễu là sai thì chẳng dạy được gì; một “don’t” trông như bản draft đầu tiên mà ai đó đã thật sự ship mới là thứ khiến guideline này bám lại được.
FAQ như một documentation pattern
Một trang FAQ riêng cho phần content của design system chứng minh được giá trị của nó ngay khi team nhận ra cùng ba, bốn câu hỏi cứ lặp đi lặp lại trong quá trình onboarding — trên Slack, trong comment code review, trong buổi design critique. Thay vì trả lời lại từ đầu “cái này nên là toast hay banner?” hay “button label có viết hoa chữ cái đầu mỗi từ không?” mỗi lần, một FAQ được duy trì tốt biến mỗi câu hỏi lặp lại thành một câu trả lời cố định, có thể link đến.
Pattern này hoạt động tốt nhất khi nó thực sự bắt nguồn từ những câu hỏi thật, lặp lại thật, chứ không phải phỏng đoán của người duy trì tài liệu về việc người ta có thể hỏi gì — cách nhanh nhất để xây dựng một FAQ là giữ một log liên tục ghi lại mọi câu hỏi liên quan đến content xuất hiện trên Slack hoặc PR review trong một tháng, rồi viết ra những câu lặp lại. Nó cũng hoạt động tốt nhất khi ngắn gọn và cụ thể:
- “Cái này nên viết sentence case hay title case?” → trả lời bằng quy tắc và một ví dụ, không phải một bài luận về lịch sử typography.
- “Tôi có được dùng dấu chấm than không?” → trả lời bằng những bối cảnh cụ thể được phép (thành công lần đầu, hoàn tất onboarding) và những bối cảnh không được phép (error, bất cứ gì liên quan đến tiền hoặc mất dữ liệu).
- “Chúng ta gọi tính năng/khái niệm này là gì?” → link thẳng đến terminology glossary thay vì tranh luận lại về naming ngay trong FAQ.
- “Tôi hỏi ai nếu tình huống của tôi không được đề cập ở đây?” → một FAQ đúng nghĩa luôn nên kết thúc bằng một escalation path, vì không có guideline nào lường trước được mọi trường hợp, và một ngõ cụt ở đây chỉ đẩy contributor quay lại đoán mò.
FAQ là một pattern giảm nhẹ triệu chứng, không phải thay thế cho tài liệu chính tốt — nếu FAQ phình to quá 15–20 mục, đó thường là dấu hiệu một số câu trả lời trong đó xứng đáng được nâng cấp thành section riêng trong guideline chính thay vì nằm mãi như một danh sách tribal knowledge cuộn dài.
Content design như một discipline có stakeholder riêng
Một design system coi content như thứ mà engineer gõ hoặc designer liếc qua vào cuối dự án đang thiếu mất một stakeholder: UX writer (còn gọi là content designer hoặc content strategist), người có vai trò ngang hàng với visual và interaction designer trong hệ thống, không phải cấp dưới. Cũng như design system cần một interaction designer quyết định component hoạt động ra sao và một engineer quyết định nó được triển khai thế nào, nó cần một UX writer quyết định nó nên được diễn đạt ra sao — và quyết định đó có mức độ chặt chẽ và số lượng edge case chẳng kém gì một interaction spec.
Cụ thể, phần đóng góp của UX writer trong hệ thống bao gồm:
- Sở hữu và duy trì voice/tone guidelines cùng terminology glossary như những tài liệu sống, không phải một deliverable làm một lần rồi thôi.
- Review component spec về copy mặc định và copy props (tài liệu của một button component nên đi kèm hướng dẫn thế nào là một label tốt, y hệt cách nó đi kèm hướng dẫn khi nào dùng visual style primary so với secondary).
- Ngồi cùng những buổi design critique và governance forum của design system như visual/interaction designer, với thẩm quyền chặn một pattern đã ship nếu copy của nó vi phạm guideline, y hệt cách một designer có thể chặn một pattern có visual style vi phạm token system.
- Hợp tác với engineer cụ thể về nội dung error message, vì raw backend error string lộ ra đến end user là một trong những content failure phổ biến và gây hại nhất, và sửa nó đòi hỏi UX writer và engineer đồng thuận về một lớp chuyển đổi giữa system error và message hiển thị cho người dùng.
Điều này khớp với mô hình stakeholder được mô tả trong Xây dựng Design System: một hệ thống bền vững cần có đại diện của design, engineering, và content ngay từ đầu, không phải gắn content vào sau khi component API đã đóng băng. Một hệ thống mà người đóng góp content duy nhất là “ai rảnh thì làm” sẽ tiếp tục tái sinh đúng vấn đề thiếu nhất quán mà note này mở đầu — không phải vì ai đó bất cẩn, mà vì không ai sở hữu phần chữ theo cách ai đó sở hữu spacing token.
Bảng tra nhanh: content element → guideline → ví dụ
| Content element | Guideline | Ví dụ |
|---|---|---|
| Button label | Verb + noun, nêu rõ hành động cụ thể, không dùng “OK”/“Submit” mơ hồ cho hành động có hệ quả | ”Send invite,” “Delete project,” “Save changes” |
| Error message | Nêu điều gì đã xảy ra (ngôn ngữ dễ hiểu) + tại sao (nếu biết/hữu ích) + tiếp theo làm gì; không đổ lỗi, không vui vẻ giả tạo | ”Chúng tôi chưa lưu được thay đổi của bạn. Kiểm tra kết nối mạng và thử lại.” |
| Empty state | Giải thích cái gì đang thiếu và đưa ra hành động tiếp theo cụ thể, đừng để người dùng ở ngõ cụt | ”Bạn chưa tạo project nào. Tạo project đầu tiên để bắt đầu.” |
| Placeholder text | Hiện một ví dụ input/format hợp lệ, không bao giờ thay thế label cố định của field | ”vd: jane@company.com” (kèm label hiển thị riêng “Địa chỉ email”) |
| Tooltip | Một câu ngắn, cụ thể, thêm thông tin chưa hiển thị sẵn — không lặp lại label | Trên nút bị disable: “Bạn cần quyền admin để publish trang này” (không phải “Nút này đang bị disable”) |
| Xác nhận thành công | Xác nhận hành động và, nếu không hiển nhiên, cả hệ quả của nó | ”Đã lưu thay đổi. Đồng nghiệp của bạn sẽ thấy cập nhật này ngay lập tức.” |
| Xác nhận hành động destructive | Nêu rõ thứ cụ thể bị xóa; tránh “Bạn có chắc không?” chung chung không có đối tượng | ”Xóa project? Hành động này không thể hoàn tác.” |
| Trạng thái loading/progress | Thiết lập kỳ vọng về thời gian chờ hoặc bước tiếp theo khi thời gian chờ đáng kể | ”Đang tải file lên — có thể mất một phút với video lớn” |
Best Practices
Cho content cùng một cổng review như component. Một pull request thêm error message mới hoặc button label mới nên được review dựa trên cùng chuẩn văn bản như một pull request thêm component variant mới — không để mặc gu cá nhân quyết định. Nếu không có ai review theo chuẩn đó, ít nhất hãy link guideline mà copy đó nên tuân theo.
Viết ví dụ “don’t” cẩn thận như ví dụ “do,” và làm nó thực tế. Một “don’t” kiểu strawman (“SYSTEM ERROR 0x8004” làm phản ví dụ cho error message thân thiện) chẳng dạy được gì, vì chẳng ai viết như vậy. “Don’t” hữu ích là lỗi lầm khả dĩ — nút “Submit” chung chung, câu “Invalid input” đúng về kỹ thuật nhưng vô ích — mà một contributor hợp lý có thể thật sự ship dưới áp lực thời gian.
Không bao giờ để lộ raw system error ra cho người dùng. Mọi error path trong sản phẩm nên đi qua một lớp chuyển đổi ánh xạ system/backend error thành message hiển thị cho người dùng theo cấu trúc “điều gì đã xảy ra, tại sao, tiếp theo làm gì” — coi một error state chưa được ánh xạ là bug, không phải fallback chấp nhận được.
Giữ một terminology glossary sống và tham chiếu đến nó, đừng tự suy diễn lại mỗi feature. Nếu “workspace” là thuật ngữ chuẩn, copy của mọi feature mới nên link đến hoặc kiểm tra glossary trước khi đưa “project,” “org,” hay “team” vào như từ đồng nghĩa cho cùng khái niệm (xem phần thảo luận về naming/terminology trong Design Language & Nguyên tắc thiết kế).
Audit copy đã ship định kỳ, không chỉ ở thời điểm thiết kế. Copy có xu hướng trôi dạt sau khi launch khi engineer sửa message trực tiếp trong code mà không qua content review. Một đợt audit mẫu hàng quý với error message và empty state đang live sẽ bắt được sự trôi dạt đó, y hệt cách visual QA bắt được lỗi dùng sai token.
Localize tone một cách có chủ đích, không chỉ localize từ ngữ. Một tone nghe “thân thiện” trong tiếng Anh (cách diễn đạt suồng sã, contraction, thỉnh thoảng có dấu chấm than) có thể nghe thiếu chuyên nghiệp hoặc thậm chí bất kính khi dịch nguyên văn sang ngôn ngữ hoặc văn hóa khác. Voice và tone guidelines nên đánh dấu rõ những lựa chọn tone mang tính đặc thù văn hóa cần được diễn giải lại chứ không chỉ dịch lại, trong quá trình localization.
Đưa UX writer (hoặc vai trò tương đương) vào ngay từ đầu khi làm component/pattern mới, không phải ở cuối. Copy guidance được gắn thêm vào sau khi component đã ship thường chỉ mang tính thẩm mỹ (sửa từng chuỗi lẻ) chứ không mang tính cấu trúc (sửa thiết kế prop nền tảng, ví dụ một component chỉ hỗ trợ một prop message chung chung thay vì các prop title/description/action riêng biệt cần thiết để viết một error message đàng hoàng).
Đừng nhầm lẫn giữa có một style guide và có một style guide được thực thi. Một content style guide tồn tại nhưng không được link từ tài liệu component, không nằm trong checklist code review, và không được nhắc đến khi onboarding chỉ là một tài liệu, không phải một hệ thống. Hãy đối xử với việc áp dụng nó giống cách phần còn lại của design system đối xử với việc áp dụng component — thứ cần đo lường, không phải mặc định cho là có (xem Đo lường thành công: Analytics & Testing về cách hệ thống theo dõi xem guidance của nó có thực sự được tuân theo hay không).
Tài liệu tham khảo
- Mailchimp Content Style Guide
- Google Developer Documentation Style Guide — UX writing basics
- Material Design — Writing guidelines
- Atlassian Design System — Content
- Shopify Polaris — Content guidelines
- GOV.UK Design System — Content design
- Microsoft Writing Style Guide
- Nielsen Norman Group — Microcopy: The Complete Guide
Part of the Design System Roadmap knowledge base.
Overview
Every design system spends real effort making sure a “primary button” looks the same everywhere — same corner radius, same padding, same color token. Far fewer spend the same effort making sure that button says the same kind of thing everywhere. One screen says “Submit,” another says “Send Request,” a third says “OK, do it!” One error message says “Error: 400 Bad Request,” another says “Oops! Something went wrong 😅,” a third quietly says nothing at all. None of these are visual inconsistencies — the buttons are pixel-identical — but the product still feels like it was built by five different teams who never talked to each other, because the words disagree about who the product is.
That’s the core argument for putting content in the design system rather than leaving it to whoever is typing that day: words are UI. A user reads a button label, an error message, or an empty state before they notice its color or its shadow, and inconsistent terminology or tone erodes trust in exactly the same way an inconsistent visual language does — it just does so more subtly, because nobody files a bug ticket that says “this copy feels off.” A design system’s job is to make good decisions the default and bad ones effortful; content deserves the same guardrails as color and spacing. This note covers how to document the system itself well, how to write voice and tone guidelines that actually change what people type, how to write microcopy for buttons, errors, empty states, and placeholders, and how content design fits into a design system as a discipline with its own dedicated contributors — UX writers — alongside visual and interaction designers and engineers.
Fundamentals
Why content belongs in the design system
A design system that ships components but not content guidance solves half the consistency problem and quietly reintroduces the other half. Consider what actually varies across a product when content is left unowned:
- Terminology drifts. One team calls it a “workspace,” another calls the same concept a “project,” a third calls it an “org.” Users build a mental model from whichever term they saw first, and every inconsistency forces them to re-verify that the new term doesn’t mean something different.
- Tone drifts. A confirmation dialog in one part of the product is brisk and functional; the same kind of dialog three screens later is chatty and full of exclamation points. Read back to back, the product feels like it has multiple personalities, because it does.
- Quality drifts. Without a shared bar, some copy gets real editorial attention and some gets whatever the engineer typed while wiring up the API response — often literally the raw error string from a backend service, surfaced directly to a user who has no idea what a
NullPointerExceptionis.
None of these failures show up in a visual QA pass. A screen can be pixel-perfect against a Figma spec and still fail the user the moment they read it. This is why mature design systems (Atlassian, Shopify Polaris, IBM Carbon, GOV.UK Design System) all ship dedicated content guidelines or voice and tone sections with the same authority as their component specs — not as an afterthought appendix, but as a peer discipline that a contributor is expected to check before shipping copy, the same way they’d check a spacing token before shipping a margin.
The practical consequence: content guidelines belong in the same system, with the same governance, versioning, and review process as components (see Building a Design System and its stakeholder model, and Component Guidelines & Documentation Patterns for how component-level docs are structured — content guidelines follow the same discipline, just for words instead of props).
Writing the system’s own documentation well
Before a design system can tell contributors how to write good copy, its own documentation has to model that standard — a content guidelines page full of vague, jargon-heavy prose undermines its own advice. A few properties separate documentation that actually gets used from documentation that gets skimmed once and ignored:
- Task-oriented headings, not topic-oriented ones. A heading like “Buttons” makes a reader search the whole section to find what they need. A heading like “Writing a button label” or “When to use a confirmation dialog vs. a toast” answers the question the reader actually has, which is almost always “what do I do right now, in this specific situation?”
- Lead with the answer, not the theory. State the “when to use this” answer in the first sentence or two, then justify it. A reader deciding between an error banner and a toast notification should get “Use a banner when the error blocks the user from continuing; use a toast when it doesn’t” in the opening line — the reasoning and edge cases can follow, but the decision shouldn’t be buried under three paragraphs of background.
- Runnable, real examples — not placeholder Lorem Ipsum. A code example that shows
<Button label="Click here" />teaches nothing about good microcopy; it should show<Button label="Save changes" />and, ideally, a rejected alternative next to it. The same logic extends beyond code snippets to voice/tone examples: a documented “don’t” should be a realistic sentence a contributor might actually type, not a strawman no one would write. - Searchable and scannable. Long paragraphs of unbroken prose bury the specific rule someone is looking for. Short sections, clear headings, and a table for anything with more than three comparable rows (tone examples, error message patterns, terminology) let a contributor scan to the relevant row instead of reading top to bottom every time.
- Kept close to where it’s used. Guidance that lives only in a wiki nobody remembers to check gets ignored; guidance surfaced in the component’s own documentation page (e.g., a “Writing guidelines” tab right next to the “Props” tab in a Button component’s docs) gets read at the moment it’s actually needed.
Key Concepts
Voice vs. tone
The single most useful distinction in content design is the one between voice and tone, because conflating them is the most common reason teams either over-standardize (every message sounds robotic and identical) or under-standardize (every message sounds like a different product).
Voice is the product’s consistent personality — it doesn’t change based on context, the same way a person’s core personality doesn’t change depending on who they’re talking to. Is the product formal or casual? Direct or explanatory? Confident or deferential? A product’s voice is decided once (ideally alongside the brand values and design principles work — see Design Language & Principles) and then applied everywhere.
Tone is voice adjusted for context. The same product, with the same underlying personality, sounds different when celebrating a success than when reporting a failure — not because it has multiple personalities, but because a good communicator naturally modulates delivery based on the situation and the reader’s emotional state at that moment. An error message and a success message share the product’s voice (say, “clear and matter-of-fact”) but take different tones: the success message can afford warmth and brevity, while the error message needs to be calmer, more careful, and more informative because the reader is more likely to be frustrated or anxious.
| Aspect | Voice | Tone |
|---|---|---|
| Changes with context? | No — constant across the whole product | Yes — adjusts to the situation |
| Analogy | A person’s core personality | How that person adjusts delivery: comforting a friend vs. giving a work update |
| Example | ”We write like a knowledgeable friend, not a legal department” | That same friend sounds encouraging in an empty state, apologetic and precise in an error, celebratory but brief in a success toast |
| Where it’s defined | Brand/content strategy, alongside design principles | Per-context guidance: error messages, success states, onboarding, destructive actions |
| Governance | Rarely changes | Reviewed and expanded as new contexts/components are added |
A useful test for whether a team actually has a distinct voice and tone (rather than one generic “be nice” instruction): read three pieces of copy from very different contexts — an error message, a marketing empty state, and a legal/billing notice — out loud. If they sound like they were written by the same person adjusting to context, voice and tone are both working. If they sound interchangeable with a competitor’s copy, or like three unrelated writers, the system needs sharper definition on one or both.
Microcopy guidelines
Microcopy is the small, high-frequency text that carries an outsized share of a product’s perceived quality, because it appears constantly and at moments when the user is trying to accomplish something specific: button labels, error messages, empty states, and placeholder text. Each has its own failure modes and its own rule of thumb.
Button labels: verb + noun, be specific about the action. A label should tell the user exactly what will happen when they click it, not just that something will happen. “Submit” and “OK” are vague enough to require the user to re-read the surrounding context to remember what they’re actually agreeing to; “Save changes,” “Delete project,” and “Send invite” are unambiguous on their own, which matters most in exactly the moments (destructive actions, irreversible actions) where ambiguity is costliest.
Error messages: what happened, why, what to do next. A good error message has three jobs, and skipping any of them leaves the user stuck. It states what happened in plain language (not a raw system error), gives why when the reason is useful and knowable (not “an error occurred” with no further information), and — most important — tells the user what to do next. A message that only reports a failure without a next step turns the user into an unpaid debugger of the product. Two failure modes are worth naming explicitly because they’re common and both erode trust: blaming the user (“You entered an invalid value” when the field’s requirements were never shown) reads as hostile even when technically true, and false cheerfulness about a real failure (“Oops! 😅 Looks like something went sideways!”) reads as dismissive of a problem that may have just cost the user their work or their data.
Empty states: explain what’s missing and what to do about it, don’t just say “nothing here.” An empty state is a teaching opportunity, not a dead end — it’s often the very first thing a new user sees in a given screen, before they’ve built any mental model of what belongs there. A bare “No items” or “No results found” answers only the first half of the user’s question (what’s here — nothing) and abandons them on the second half (what do I do now?).
Placeholder text: an example of valid input, never the label itself. A placeholder should show the format or type of answer expected (e.g., “e.g., jane@company.com”) and disappear the instant the user starts typing — it is not a substitute for a persistent field label, because placeholder text vanishing on focus means a user who gets interrupted mid-form loses the only cue for what the field was asking.
Before/after: rewriting generic microcopy
Generic, system-default copy usually isn’t wrong so much as it’s a missed opportunity — it works, but it teaches the user nothing and reassures them of nothing. The rewrite is almost never longer; it’s more specific.
| Context | Before (generic) | After (clear & helpful) | Why it’s better |
|---|---|---|---|
| Save button | ”Submit" | "Save changes” | Names the exact action and its object; no need to re-read the form to know what’s being submitted |
| Destructive action | ”OK” / “Yes" | "Delete project” | An irreversible action should never hide behind a generic confirmation word |
| Form validation error | ”Invalid input" | "Enter a valid email, like jane@company.com” | States what’s wrong and shows the expected format in one line |
| Network error | ”Error: 500" | "We couldn’t save your changes. Check your connection and try again.” | Plain language, no blame, and a concrete next step |
| Empty search results | ”No results found" | "No results for “budget report” — try different keywords or check your filters” | Echoes the query so the user trusts the search actually ran, and suggests two concrete next steps |
| Empty state (first use) | “Nothing here yet" | "You haven’t created any projects yet. Create your first project to get started.” + a “Create project” button | Turns a dead end into the next action, right where the user is looking |
| Loading/processing | ”Please wait…" | "Uploading your file — this can take a minute for large videos” | Sets an expectation for duration so the user doesn’t assume the app has frozen |
| Placeholder in a date field | ”Placeholder text” (literal!) | ”MM/DD/YYYY” | Shows the exact expected format instead of a meaningless filler string |
| Success confirmation | ”Success!" | "Changes saved. Your teammates will see this update immediately.” | Confirms the action and its consequence, which matters when the effect isn’t immediately visible on screen |
Tone of voice: a practical adjective-pair framework
An abstract instruction like “be friendly” gives a writer nothing to push against — friendly compared to what? A more workable framework pairs each desired quality with the failure mode it’s guarding against, expressed as two adjectives joined by “but not.” Each pair should ship with a do/don’t example, exactly like a design principle (see Design Language & Principles for the same pattern applied to visual principles).
| Adjective pair | What it guards against | Do | Don’t |
|---|---|---|---|
| Confident, but not arrogant | Copy that sounds like it’s showing off or condescending to the user | ”Your changes are saved automatically." | "Don’t worry, we’ve got this — trust us!” |
| Friendly, but not silly | Copy that undermines its own credibility with excessive jokes or emoji, especially in serious moments | ”We hit a snag saving your file. Let’s try that again." | "Whoopsie daisy! 🙈 Our bad!” |
| Clear, but not curt | Copy so terse it reads as cold or robotic | ”This action can’t be undone. Delete the project?" | "Delete? Y/N” |
| Helpful, but not condescending | Over-explaining things the user already knows, or talking down to them | ”Passwords need at least 8 characters, including a number." | "Just so you know, most people forget to include a number in their password, so make sure you don’t make that mistake!” |
| Human, but not unprofessional | Casual language that undercuts trust in a serious context (billing, legal, security) | “Your card was declined. Try another payment method or contact your bank." | "Yikes, your card got rejected lol, try another one?” |
| Concise, but not vague | Brevity achieved by cutting the information the user actually needs | ”Upload a JPG or PNG under 5MB." | "Upload a valid file.” |
The exercise for a team writing its own version of this table is the same discipline used for design principles: pick 4–6 adjective pairs that reflect the brand’s actual values (not a generic list copied from another company’s guide), and for each one, write a “don’t” example that’s realistic — something a well-meaning contributor might genuinely type under deadline pressure — rather than an exaggerated strawman nobody would write. A “don’t” that’s too obviously bad teaches nothing; a “don’t” that looks like a first draft someone actually shipped is what makes the guideline stick.
FAQs as a documentation pattern
A dedicated FAQ page for the design system’s content section earns its keep once a team notices the same three or four questions being asked repeatedly during onboarding — in Slack, in code review comments, in design critiques. Rather than re-answering “should this be a toast or a banner?” or “do we capitalize button labels?” from scratch every time, a maintained FAQ turns each recurring question into a permanent, linkable answer.
The pattern works best when it’s genuinely driven by real, repeated questions rather than a maintainer’s guess at what might be asked — the fastest way to build one is to keep a running log of every content-related question that comes up in Slack or PR review for a month, then write up the ones that repeat. It also works best kept short and specific:
- “Should this be sentence case or title case?” → answer with the rule and one example, not a essay on typography history.
- “Can I use an exclamation point?” → answer with the specific contexts where it’s allowed (a first-time success, an onboarding completion) and where it isn’t (errors, anything involving money or data loss).
- “What do we call this feature/concept?” → link directly to the terminology glossary rather than re-litigating naming in the FAQ itself.
- “Who do I ask if my situation isn’t covered here?” → a genuine FAQ should always end with an escalation path, because no guideline anticipates every case, and a dead end here just pushes the contributor back to guessing.
An FAQ is a symptom-relief pattern, not a substitute for good primary documentation — if the FAQ balloons past 15–20 entries, that’s usually a sign some of those answers deserve to be promoted into proper sections of the main guidelines rather than living as a scrolling list of tribal knowledge.
Content design as a discipline with its own stakeholders
A design system that treats content as something engineers type or designers eyeball at the end of a project is missing a stakeholder: the UX writer (also called a content designer or content strategist), whose role in the system is a peer to the visual and interaction designer’s, not a subordinate one. Just as a design system needs an interaction designer to decide how a component behaves and an engineer to decide how it’s implemented, it needs a UX writer to decide how it should be worded — and that decision has just as much rigor and just as many edge cases as an interaction spec.
Concretely, a UX writer’s stake in the system includes:
- Owning and maintaining the voice/tone guidelines and the terminology glossary as living documents, not a one-time deliverable.
- Reviewing component specs for their default copy and copy props (a button component’s documentation should ship with guidance on what makes a good label, the same way it ships with guidance on when to use the primary vs. secondary visual style).
- Sitting in the same design critiques and design system governance forums as visual/interaction designers, with the authority to block a shipped pattern whose copy violates the guidelines the same way a designer can block one whose visual style violates the token system.
- Partnering with engineers on error-message content specifically, since raw backend error strings reaching end users is one of the most common and most damaging content failures, and fixing it requires the UX writer and the engineer to agree on a translation layer between system errors and user-facing messages.
This lines up with the stakeholder model described in Building a Design System: a sustainable system needs design, engineering, and content representation from the start, not content bolted on after the component API is already frozen. A system whose only content contributor is “whoever’s available” will keep reproducing the exact inconsistency problem this note opened with — not because anyone is careless, but because nobody owns the words the way someone owns the spacing tokens.
Quick-reference table: content element → guideline → example
| Content element | Guideline | Example |
|---|---|---|
| Button label | Verb + noun, name the specific action, no vague “OK”/“Submit” for consequential actions | ”Send invite,” “Delete project,” “Save changes” |
| Error message | State what happened (plain language) + why (if known/useful) + what to do next; no blame, no false cheer | ”We couldn’t save your changes. Check your connection and try again.” |
| Empty state | Explain what’s missing and give a concrete next action, don’t leave the user at a dead end | ”You haven’t created any projects yet. Create your first project to get started.” |
| Placeholder text | Show an example of valid input/format, never a substitute for the field’s persistent label | ”e.g., jane@company.com” (with a separate visible label “Email address”) |
| Tooltip | One short, specific sentence that adds information not already visible — not a restatement of the label | On a disabled button: “You need admin permissions to publish this page” (not “This button is disabled”) |
| Success confirmation | Confirm the action and, if not obviously visible, its consequence | ”Changes saved. Your teammates will see this update immediately.” |
| Destructive-action confirmation | Name the specific thing being destroyed; avoid generic “Are you sure?” with no object | ”Delete project? This can’t be undone.” |
| Loading/progress state | Set an expectation for duration or next step when the wait is non-trivial | ”Uploading your file — this can take a minute for large videos” |
Best Practices
Give content the same review gate as components. A pull request that adds a new error message or button label should be reviewable against the same written standard as a pull request that adds a new component variant — not left to individual taste. If there’s no one to review it against, at minimum link the guideline the copy should follow.
Write the “don’t” example as carefully as the “do” example, and make it realistic. A strawman “don’t” (“SYSTEM ERROR 0x8004” as the counterexample to a friendly error message) teaches nothing, because no one writes that. The useful “don’t” is the plausible mistake — the generic “Submit” button, the technically-accurate-but-unhelpful “Invalid input” — that a reasonable contributor might actually ship under time pressure.
Never surface a raw system error to a user. Every error path in the product should pass through a translation layer that maps system/backend errors to a user-facing message following the “what happened, why, what next” structure — treat an unmapped error state as a bug, not an acceptable fallback.
Keep a living terminology glossary and reference it, don’t re-derive it per feature. If “workspace” is the canonical term, every new feature’s copy should link to or check the glossary before introducing “project,” “org,” or “team” as a synonym for the same concept (see the naming/terminology discussion in Design Language & Principles).
Audit shipped copy periodically, not just at design time. Copy tends to drift after launch as engineers patch messages directly in code without a content review pass. A quarterly sample audit of live error messages and empty states catches drift the same way a visual QA pass catches token misuse.
Localize tone deliberately, not just words. A tone that reads as “friendly” in English (casual phrasing, contractions, the occasional exclamation point) can read as unprofessional or even disrespectful once translated literally into another language or culture. Voice and tone guidelines should flag which tone choices are culturally specific and need re-interpretation, not just re-translation, during localization.
Involve a UX writer (or equivalent) from the start of a new component or pattern, not at the end. Copy guidance retrofitted onto an already-shipped component tends to be cosmetic (fixing individual strings) rather than structural (fixing the underlying prop design, e.g., a component that only supports a single generic message prop instead of separate title/description/action props needed to write a proper error message).
Don’t confuse having a style guide with having an enforced one. A content style guide that exists but isn’t linked from component documentation, isn’t part of code review checklists, and isn’t referenced in onboarding is a document, not a system. Treat its adoption the same way the rest of the design system treats component adoption — something to measure, not assume (see Measuring Success: Analytics & Testing for how a system tracks whether its guidance is actually followed).
References
- Mailchimp Content Style Guide
- Google Developer Documentation Style Guide — UX writing basics
- Material Design — Writing guidelines
- Atlassian Design System — Content
- Shopify Polaris — Content guidelines
- GOV.UK Design System — Content design
- Microsoft Writing Style Guide
- Nielsen Norman Group — Microcopy: The Complete Guide