1---
2name: ui-copy
3description: Write the words a user reads on screen — button and menu labels, empty states, error and refusal text, tooltips, hint text, placeholders, dialog titles, toasts, status lines, onboarding panels. Read this BEFORE typing any string a person will read, including a one-word label, and before reviewing or rewriting existing copy. Triggers on writing or editing UI text, microcopy, error messages, empty states, confirmation dialogs, or any user-visible string in a component, view, or copy module.
4---
5
6# UI copy
7
8Two jobs. **Writing a string** is the common case and comes first. **Reviewing
9existing strings** is the appendix at the end.
10
11Most rules here are quoted from published design systems and carry a source.
12Where the guides genuinely disagree, that is recorded as a split rather than
13resolved — pick per project and stay consistent.
14
15---
16
17## Writing a string
18
19Work in this order. The order matters: the slot determines the budget, and the
20budget does most of the work that taste otherwise has to.
21
221. **Name the slot.** Button, error, empty state, hint, tooltip, toast, title.
23 Each has a different published shape and length; they are not
24 interchangeable.
252. **Take the budget** from the table below, before writing.
263. **Write the shortest true version** that fits.
274. **Run the two checks** (below). Most strings pass and are done.
28
29### The two checks
30
31**Check 1 — can the reader act on it?** Cut anything the reader cannot act on.
32
33> "Avoid providing details that aren't essential for the user to know, such as
34> how an action or process is performed."
35> Do: "Preparing video…" Don't: "Buffering…"
36> Do: "This command isn't supported on your phone."
37> Don't: "This command is only supported on dual-core devices."
38> — [Material 2](https://m2.material.io/design/communication/writing.html)
39
40**Check 2 — is it in the reader's terms or the system's?**
41
42> "**Use user-centered explanations.** Describe the problem in terms of user
43> actions or goals, not in terms of what the software is unhappy with."
44> — [Microsoft](https://learn.microsoft.com/en-us/windows/win32/uxguide/mess-error)
45
46Also: "Use words, phrases, and concepts familiar to the user, rather than
47internal jargon" ([NN/g heuristic
48#2](https://www.nngroup.com/articles/ten-usability-heuristics/)).
49
50### Budgets
51
52Verified numbers only. Where a guide publishes no number, none is invented.
53GOV.UK, Polaris, and Mailchimp publish **no** length budget for buttons,
54errors, or hint text — do not cite one to them.
55
56| Slot | Budget | Source |
57|---|---|---|
58| Action label / CTA | 1–2 words | Atlassian, Carbon, Apple |
59| Message or dialog title | 3–4 words, excluding a/an/the | Atlassian |
60| Message body | 1–2 sentences | Atlassian |
61| Empty-state description | sentences under 14 words | [Stripe](https://docs.stripe.com/stripe-apps/patterns/empty-state.md) |
62| Hint text | a single short sentence, no full stop | [GOV.UK](https://design-system.service.gov.uk/components/text-input/) |
63| Icon tooltip | one- or two-word description | Carbon |
64| Tooltip (general) | 60–75 characters | Apple |
65| Toast / inline error | 2 / 3 lines maximum | Carbon |
66| Notification | title <29, collapsed <40, expanded <80 chars | Material 3 |
67| Progress label / tag | 16 / 20 characters | Carbon |
68| Any sentence | split if over 25 words | [GOV.UK](https://guidance.publishing.service.gov.uk/writing-to-gov-uk-standards/writing-guidelines/clear-language/) |
69| Clauses per sentence | avoid more than three, better not more than two; one verb per sentence | [Microsoft](https://learn.microsoft.com/en-us/style-guide/global-communications/writing-tips) |
70| Page title | ≤65 characters including spaces | GOV.UK |
71
72Leave room for translation: allow ~30% extra space, 200% for short strings
73([Microsoft](https://learn.microsoft.com/en-us/windows/win32/uxguide/text-ui)).
74
75---
76
77## Errors and refusals
78
79### Structure: what happened, then how to fix it
80
81Unanimous across seven independent guides — GOV.UK ("explain what went wrong
82and how to fix it"), Polaris, Carbon ("First, inform the user what has
83happened, then provide guidance on next steps"), Atlassian, Microsoft
84("A problem. A cause. A solution."), NN/g heuristic #9, Apple.
85
86Apple's framing test: *"That password is too short"* is less helpful than
87*"Choose a password with at least 8 characters."*
88
89### The cause is required — but constrained
90
91**Do not delete the "why".** Microsoft lists a cause as one of three required
92parts; Apple's alert title should describe "what happened, the context in which
93it happened, and why"; Atlassian requires "the reason for the error"; NN/g
94lists "concisely educate on how the system works" as a guideline. Polaris makes
95it conditional: explain what happened behind the scenes "when it's helpful to
96merchants or you can't offer a solution."
97
98Four constraints keep the cause from becoming an essay:
99
100- **User terms, not system terms** (Check 2 above).
101- **Only if it changes what they do next.** If it does not, it fails Check 1.
102- **Not if the fix already implies it.** > "Don't provide a solution if it can
103 be trivially deduced from the problem statement." —
104 [Microsoft](https://learn.microsoft.com/en-us/windows/win32/uxguide/mess-error)
105- **Never invented.** "If you don't know the reason for an error, don't make
106 one up — just say that something's gone wrong and offer a solution."
107 (Atlassian). Polaris's fallback string: "Something went wrong. Refresh your
108 browser to try again."
109
110### A refusal without an exit is a defect
111
112Carbon: "User actions are mandatory for error messages"; its Don't example is
113the bare "Instance was not created." GOV.UK bans the no-exit strings outright:
114*An error occurred*, *Answer the question*, *Select an option*, *Fill in the
115field*, *This field is required*.
116
117### Some refusals should not be error messages at all
118
119> "Do not use error messages to tell a user that they are not eligible or do
120> not have permission to do something. Or to tell them about a lack of capacity
121> or other problem the user cannot fix — because the problem is with the
122> service rather than with the information the user has provided. Instead, take
123> the user to a page that explains the problem… and provides useful information
124> about what to do next."
125> — [GOV.UK](https://design-system.service.gov.uk/components/error-message/)
126
127Before writing a permission, eligibility, or capacity refusal, ask whether the
128dialog is the wrong container.
129
130### Instruction vs description
131
132> "use an instruction for empty fields like 'Enter your name', but a
133> description like 'Name must be 35 characters or less' for entries that are
134> too long"
135> — GOV.UK. Also: error messages should reuse the language of the question or
136> label they belong to.
137
138### Words the guides ban outright
139
140GOV.UK (errors): *forbidden*, *illegal*, *prohibited*, *you forgot*, *please*
141("implies a choice"), *sorry* ("does not help fix the problem"), *valid* /
142*invalid*, *oops*.
143
144Microsoft substitutions: error, failure → **problem**; failed to → **unable
145to**; illegal, invalid, bad → **incorrect**; abort, kill, terminate → **stop**;
146catastrophic, fatal → **serious**.
147
148NN/g: "Avoid humor since it can become stale if users encounter the error
149frequently."
150
151---
152
153## Empty states
154
155**They need text.** This is the one place the "delete it" instinct is wrong.
156
157> "Do not default to totally empty states. This approach creates confusion for
158> users, who may be left wondering if the system is still loading information
159> or if errors have occurred."
160> — [NN/g](https://www.nngroup.com/articles/empty-state-interface-design/)
161
162The most operational published spec, from
163[Stripe](https://docs.stripe.com/stripe-apps/patterns/empty-state.md):
164
165```
166Title State what's missing. Short phrase. No promotion, no explanation.
167 good "No successful payments."
168 bad "Try creating your first payment to get started!"
169 "No transactions yet." beats "No transactions"
170Description When and how data will appear. Sentences under 14 words. Active voice.
171Action Must answer the title (call-and-response):
172 "No customers yet." -> "Add customer", not "Get started"
173Filtered empty is not empty. Render order: loading -> error -> empty -> content
174```
175
176Carbon adds: write it as a positive statement — "Start by adding data assets"
177beats "You don't have any data assets." Its one licence for near-silence is
178narrow: supplementary text can go when next steps are impossible (an alerts
179view with nothing triggered). No source authorizes zero pixels.
180
181---
182
183## Other slots
184
185**Buttons.** `{verb} + {noun}`, no articles — Polaris and Carbon give the
186identical formula with the same exception list (Save, Close, Cancel, OK, Done,
187Add, Delete). Atlassian: "Avoid articles in buttons, labels, and action-based
188headings" — "Create password", not "Create a password". Name the outcome;
189destructive actions use the destructive word.
190
191**Hint text.** Justified only for what the label cannot carry: how the data
192will be used, where to find it, or an example of an unfamiliar format. One
193short sentence, no full stop, no links (screen readers announce link text
194without signalling it is a link). Longer help is **promoted** to page body
195above the field, not deleted. Restating the label is the named failure mode —
196NN/g's example is an info tip reading "Enter the city of your birth" beside a
197field labelled *City of Birth*.
198
199**Placeholders.** Never a label, never the hint. Unanimous. GOV.UK renders none
200at all; NN/g and Carbon permit one only in addition to a persistent visible
201label. Do not put required information there.
202
203**Tooltips.** Never essential ("Don't use tooltips for information that is
204vital to task completion" — NN/g; Carbon, Polaris, and Material agree), never
205redundant with a visible label (Atlassian, Material, Apple, NN/g), and length
206is a design smell: "Long tooltip content is hard to read and suggests the
207information might need a more prominent placement" (Polaris); "If you need a
208lot of text to describe a control, consider simplifying your interface design"
209(Apple).
210
211**Icon-only controls.** Ambiguity escalates to a *visible* label, not a longer
212tooltip. NN/g: "Icon labels should be visible at all times, without any
213interaction from the user." Atlassian's five-second rule: if it takes more than
214five seconds to think of an appropriate icon, use a text label. See the
215accessibility floor below — the accessible name is not optional.
216
217**Link labels.** NN/g's four Ss — specific, sincere, substantial, succinct — and
218deliberately **no word cap**: "link length is less important than a good link
219description", illustrated with an approved eleven-word link
220([NN/g](https://www.nngroup.com/articles/better-link-labels/)). Do not trim a
221link to fit a budget that was written for buttons.
222
223**Confirmations.** Routine and reversible actions get no confirmation and no
224toast; offer undo instead. NN/g: "Do not use confirmation dialogs for routine
225actions. Like in Aesop's fable, if you cry wolf too many times, people will
226stop paying attention." Apple: "Avoid using an alert merely to provide
227information… Avoid explaining alert buttons." Name the irreversible consequence
228plainly; buttons name outcomes, not OK/Cancel.
229
230**Loading and status.** One gerund. Do not narrate stages unless the wait is
231long and the stages are genuinely different. Do not over-toast: "For a user
232that is saving a lot of items to their favorites, this can be a bothersome and
233intrusive way of providing feedback" (NN/g).
234
235---
236
237## When there should be no text
238
239Text competes with text. NN/g heuristic #8: "Every extra unit of information in
240an interface competes with the relevant units of information and diminishes
241their relative visibility" — framed as signal (high informational value) versus
242noise, not as word count.
243
244Delete or promote, in rough order of how often it goes wrong:
245
2461. Hint text restating the label.
2472. A tooltip duplicating a visible label, or any tooltip on an unambiguous icon.
2483. A toast or status line narrating a change already visible on screen.
2494. An instructional paragraph above a form restating what the controls do.
2505. Prose in an empty state — shorten, do not remove.
251
252Deferring beats deleting where the information is real: "Initially, show users
253only a few of the most important options. Offer a larger set of specialized
254options upon request" ([NN/g progressive
255disclosure](https://www.nngroup.com/articles/progressive-disclosure/)).
256
257Icon-vs-label, page structure, and disclosure are interface-design decisions
258rather than copy decisions; this skill only covers the words.
259
260### The accessibility floor — text that must not be cut
261
262_**Never remove these as "redundant". They are load-bearing for users you
263cannot see.**_
264
265- **Accessible name on any icon-only control.** WCAG 1.1.1: "If non-text
266 content is a control… then it has a name that describes its purpose"; 4.1.2
267 makes it programmatically determinable. The name describes the *action*, not
268 the picture. If the icon sits beside a visible text label, the icon itself
269 takes `alt=""`.
270- **Status messages.** WCAG 4.1.3 — deleting a status message is legal;
271 rendering it visually **without** a live region is not. Visually obvious is
272 explicitly not sufficient.
273- **Error text.** WCAG 3.3.1: a detected input error "is identified and the
274 error is described to the user in text". 3.3.3 requires a correction
275 suggestion where one is known.
276- **Field labels.** WCAG 1.3.1 requires a programmatically associated label; a
277 placeholder is neither persistent nor a label. A visually hidden label is
278 still announced.
279- **Hover/focus content.** WCAG 1.4.13 — custom tooltips must be dismissible,
280 hoverable, and persistent; no interactive content inside them.
281
282Note WCAG 2.5.3 Label in Name does **not** apply to icon-only controls — it
283constrains icon-plus-label pairs.
284
285---
286
287## Where the guides disagree
288
289Do not launder these into false consensus. Follow the project's existing
290convention; if there is none, pick one and apply it everywhere.
291
292| Question | The split |
293|---|---|
294| Title vs sentence case | Apple and Salesforce mandate title case for buttons and menu items; Microsoft, Material, Carbon, Atlassian, Polaris, GOV.UK all mandate sentence case |
295| Ellipsis on a button that opens a dialog | Apple requires it; Material forbids it |
296| Em dash | Material restricts ("best avoided in UX writing"); Microsoft and Mailchimp recommend it; Polaris and Atlassian allow it conditionally; Carbon and GOV.UK are silent |
297| Em dash spacing | Polaris unspaced, Atlassian spaced |
298| Ranges | Polaris en dash ("2006–2013"); Atlassian and GOV.UK spell "to" |
299| "we" in error messages | Atlassian requires it (avoids blaming the user); Polaris forbids it unless the company is at fault |
300| Period on a fragment title | Everyone says no; Stripe's empty-state spec says yes |
301| Colon after a field label | Material says skip; Win32 requires it for assistive tech |
302| Explaining internals | Atlassian bans technical information in the message; NN/g endorses "concisely educate on how the system works" |
303| Politeness | Material bans *please* / *sorry* / *thank you* in errors; Carbon permits *please* when the user is inconvenienced; Microsoft permits *sorry* only for a serious problem |
304
305The one convergent punctuation rule, reached independently by Polaris and
306Atlassian: **prefer two sentences over a dash.** Polaris — "Use an em dash only
307if you can't make your message clearer by splitting it into two sentences."
308
309**Periods**: no period on fragments, headings, titles, tooltips, field
310descriptions, or list items of three words or fewer; periods are fine once
311there are two or more sentences. Microsoft, Polaris, Atlassian, Material, and
312Apple agree (Stripe's empty-state title is the documented exception).
313
314---
315
316## Appendix: reviewing existing copy
317
318Use this on a review pass, not while writing.
319
320**The register tell.** Copy drafted by a language model tends to state a fact
321and then append a justification for it, in the voice of a design document
322rather than a product. The joints are an em dash, a `, so`, or a bare
323appositive:
324
325```
326"Reconnecting — this transcript may be behind."
327"No host is connected, so there is no conversation to show."
328"A chat runs in a project's track, so there is nowhere for one to go."
329```
330
331Each fails Check 1 or Check 2 above: it explains mechanism the reader cannot
332act on, in the system's terms rather than theirs. Note the em dash itself is
333**not** the defect — it is only where the clause attaches, and two respected
334guides recommend em dashes. Judge the clause, not the punctuation.
335
336*This section is the one part of this skill with no published prior art behind
337it. Corpus work on LLM prose covers long-form writing only, and no design
338system addresses AI-drafted strings. Treat it as a working hypothesis.*
339
340**Other things to catch on review:**
341
342- A docket of non-events: "This message was not sent." "Nothing was deleted."
343 Prefer "Not sent", "Couldn't rename track".
344- Reassurance for a loss the reader can already see. Reassure only when the
345 loss would be invisible and is real.
346- A second clause that restates the first (Microsoft's trivially-deducible
347 rule). Note that a two-sentence message is not itself a defect — Atlassian
348 prescribes exactly two, "the most likely cause or the simplest solution in
349 the first sentence… an alternative backup solution in the second". Judge
350 whether the second sentence adds an action, not whether it exists.
351- Blaming a subsystem: "This session's host has not reported a model" →
352 "No model available".
353
354**Do not overcorrect.** These are correct and should be left alone: bare labels
355("Cancel", "Copy"/"Copied", "Running"/"Done"/"Failed", "no matches"); gerund
356plus ellipsis for waits ("Attaching…"); lowercase fragments in dense lists; and
357a detail line carrying a genuine gotcha the reader cannot see and would guess
358wrong about ("Ignored paths are not searched.").
359
360---
361
362## Where copy lives
363
364Before editing a string, find out whether it is centralized. If a project keeps
365its sentences in a copy module, a wording change is one edit; if labels are
366inlined at call sites, the same change is N edits and the duplicates will
367drift. Say which you are dealing with rather than silently editing one of two
368copies.
369
370## Source caveats
371
372Polaris, Carbon, Material 3, Atlassian, and Salesforce content pages are
373client-rendered, gated, or dead at their canonical URLs; several quotes above
374come from the design systems' own repositories or Wayback captures rather than
375the live site. Microsoft has no current error-message page — its
376cause-and-solution structure is from Win32 guidance carrying a "not updated"
377banner. The Polaris toast page is formally deprecated.