Skip to content

Content design — UX writing

foundations specs/foundations/ux-writing.kmd

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.

When this spec applies

Primary triggers

All triggers

Specification body

Spec — Content design / UX writing

Facet Visual do Koder Design. Material parity: https://m3.material.io/foundations/content-design/style-guide/ux-writing-best-practices.

Voice

Koder products speak as:

  • Knowledgeable but not condescending — explain WHAT and (when helpful) WHY, never assume the user is wrong
  • Direct, not bossy — "Save" not "You should save now"
  • Warm, not sappy — friendly without faux-cheer ("Yay!" is out)
  • Specific — "Saved at 14:32" beats "Saved successfully"
  • Confident — declarative, present tense

Tone variants

Tone shifts by context but voice stays constant.

ContextToneExample
SuccessBrief + specific"Profile updated."
ErrorHelpful + non-blaming"We couldn't reach the server. Check your connection and try again."
Empty stateInviting"No projects yet — create your first one to get started."
OnboardingEncouraging + brief"Welcome to Koder Talk. Let's pick a wake word."
Destructive confirmSerious + clear"Delete 12 messages? This can't be undone."
LoadingQuiet"Loading…" (avoid blank fluff like "Please wait while we…")

R1 — Lengths

ElementMax chars (en-US baseline)Notes
Button label24Verb-first ("Save changes", "Delete")
Tab label16Noun ("Profile", "Activity")
Field label32Noun phrase ("Display name")
Hint text80Helpful one-liner
Error message140Brief + actionable (errors/user-facing-messages.kmd)
Section title40Noun phrase
Tooltip body80Brief reinforcement
Empty state body200Inviting + 1 CTA

pt-BR translations may run +30%; design for the longer language and truncate gracefully (no clipping).

R2 — Vocabulary

Canonical terms

Koder canonicalAvoid
Sign in (not "log in")"Login", "Log in"
Sign out"Logout", "Log out"
Tenant / workspace"Account" (ambiguous with billing)
You (second person)"User", "Users" (third person) in UI
Save"Submit" (for non-form workflows)
Cancel"Discard", "Close" (use only for actually closing)
Delete"Remove" (different semantics — remove from view, not data)
Undo"Cancel" (after the fact)
Send"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

Sentence 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; pt-BR follows standard pt comma 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"); pt-BR 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 pt-BR; machine fallback marked visibly until human pass
  • ICU keys per i18n/contract.kmd R6
  • 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 aria-label
  • Error text MUST be associated with the failing field (aria-describedby)
  • Section titles MUST use semantic headings (<h2>-<h6>, never styled 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."
  • errors/user-facing-messages.kmd — error message format
  • policies/language.kmd — pt-BR / en-US per surface
  • i18n/contract.kmd — translation pipeline

References