Content design — UX writing
Voice, tone, vocabulary, and pattern guide for every user-facing string in Koder products. Material parity (`/foundations/content-design/style-guide/ux-writing-best-practices`). Extends `errors/user-facing-messages.kmd` (which covers error copy only) to all UI text — buttons, labels, hints, empty states, success messages.
Spec — Content design / UX writing
Facet *isual*do Koder Design. Material parity: https://m3.material.io/foundations/content-design/style-guide/ux-writing-best-practices.
Voice
Koder products speak as:
- *nowledgeable but not condescending*— explain WHAT and (when
helpful) WHY, never assume the user is wrong
- *irect, not bossy*— "Save" not "You should save now"
- *arm, not sappy*— friendly without faux-cheer ("Yay!" is out)
- *pecific*— "Saved at 14:32" beats "Saved successfully"
- *onfident*— declarative, present tense
Tone variants
Tone shifts by context but voice stays constant.
| Context | Tone | Example |
|---|---|---|
| *uccess* | Brief + specific | "Profile updated." |
| *rror* | Helpful + non-blaming | "We couldn't reach the server. Check your connection and try again." |
| *mpty state* | Inviting | "No projects yet — create your first one to get started." |
| *nboarding* | Encouraging + brief | "Welcome to Koder Talk. Let's pick a wake word." |
| *estructive confirm* | Serious + clear | "Delete 12 messages? This can't be undone." |
| *oading* | Quiet | "Loading…" (avoid blank fluff like "Please wait while we…") |
R1 — Lengths
| Element | Max chars (en-US baseline) | Notes |
|---|---|---|
| Button label | 24 | Verb-first ("Save changes", "Delete") |
| Tab label | 16 | Noun ("Profile", "Activity") |
| Field label | 32 | Noun phrase ("Display name") |
| Hint text | 80 | Helpful one-liner |
| Error message | 140 | Brief + actionable (errors/user-facing-messages.kmd) |
| Section title | 40 | Noun phrase |
| Tooltip body | 80 | Brief reinforcement |
| Empty state body | 200 | Inviting + 1 CTA |
pt-BR translations may run +30%; design for the longer language and truncate gracefully (no clipping).
R2 — Vocabulary
Canonical terms
| Koder canonical | Avoid |
|---|---|
| *ign in*(not "log in") | "Login", "Log in" |
| *ign out* | "Logout", "Log out" |
| *enant / workspace* | "Account" (ambiguous with billing) |
| *ou*(second person) | "User", "Users" (third person) in UI |
| *ave* | "Submit" (for non-form workflows) |
| *ancel* | "Discard", "Close" (use only for actually closing) |
| *elete* | "Remove" (different semantics — remove from view, not data) |
| *ndo* | "Cancel" (after the fact) |
| *end* | "Post" (in non-social contexts) |
Forbidden words
- "Simply", "just", "easy" — they trivialize user effort
- "Wrong", "invalid", "error" in body text — symbol + spec text per
user-facing-messages.kmd - "Whoops", "oops" — friendly to a fault; use serious calm
- "Click", "tap" — surface-neutral language ("Select", "Open")
- "Awesome", "great", "perfect" as success acknowledgment — over-praise
R3 — Capitalization
*entence case*for everything except product names and proper nouns:
- ✅ "Save changes"
- ❌ "Save Changes"
- ✅ "Sign in to Koder"
- ❌ "Sign In To Koder"
Exception: company/product names retain Title Case ("Koder Design", "Koder Talk", "Koder Flow").
R4 — Punctuation
- Period at end of complete sentences in body text
- No period at end of short titles / buttons / labels / list items
- Em dash with thin spaces: " — " (HTML entity
—) - Curly quotes for prose: " '
- Straight quotes for code only
- Oxford comma: yes (en
US convention; ptBR follows standard ptcomma rules)
R5 — Numbers
- Cardinal numerals < 10: spell out in prose ("nine items", "ten items")
- ≥ 10: numerals ("10 items", "1,234 items")
- Counts in UI labels: always numerals ("3 unread")
- Time: 24h format in en
US ("14:32"); ptBR same - Dates: ISO 8601 in technical contexts; localized friendly form in UI
R6 — Internationalization
- Strings in code: en-US source of truth
- Translations: human
translated for ptBR; machine fallback markedvisibly until human pass
- ICU keys per
i18n/contract.kmdR6 - Plurals: ICU
{count, plural, one {1 file} other {# files}} - Variables in translations:
{name}, never positional%s
R7 — Accessibility
- Visible text MUST also be readable by screen readers (no
CSS-tricks where the visible label differs from the semantic one)
- Icon
only buttons MUST have `arialabel` - Error text MUST be associated with the failing field
(
aria-describedby) - Section titles MUST use semantic headings (
<h2>-<h6>, neverstyled divs)
R8 — Examples
Button label
| ❌ | ✅ | Why |
|---|---|---|
| "OK" | "Save" | Verb-specific |
| "Click here to save" | "Save" | Concise + neutral |
| "SUBMIT" | "Send message" | Sentence case + specific verb |
Error
| "Invalid input" | "Email must include @ — try name@example.com" |
| "Wrong password" | "We couldn't sign you in. Check your password or reset it." |
| "Server error" | "Couldn't save right now. Your changes are safe locally — we'll retry automatically." |
Empty state
| "No data" | "No projects yet — create your first to get started." |
| "Empty" | "You have no scheduled messages. Schedule one from any conversation." |
Cross-link
errors/user-facing-messages.kmd— error message formatpolicies/language.kmd— ptBR / enUS per surfacei18n/contract.kmd— translation pipeline