content-design · git:20260729.071181e · 2026-07-29 · sha256 74fdc33e865e7e5f
content-design git:20260729.071181eA
Immutable. This exact content is served forever at /api/v1/blob/74fdc33e865e7e5f.
--- name: content-design description: Use when writing or reviewing any string a user reads — labels, buttons, empty states, errors, permission prompts, onboarding, notifications. Invoked by ux-architect and product-designer while specifying screens, and by product-manager when a clarification turns out to be a copy decision. Triggers the moment a placeholder string would ship. --- # Content design The interface is mostly words. Words written last, by whoever was implementing, are the ones users actually read. ## Buttons and labels - **A button says what happens when you press it.** `Save changes`, not `OK`. `Delete 3 photos`, not `Confirm`. - **A destructive button names what is destroyed and whether it comes back.** "This cannot be undone" belongs in the dialog, not in the button. - Sentence case throughout. Never end a button label with a full stop. - `Cancel` means "nothing happens". Never label a button `Cancel` when something happens. ## Errors — three parts, always 1. **What happened**, in the user's terms, not the system's. 2. **Whether their data is safe.** This is the question they are actually asking. 3. **What to do next**, as an action they can take right now. `Something went wrong` fails all three. `Couldn't save — your note is still here. Retry when you're back online.` passes all three in one line. **Never show an error code without also showing prose**, and never show raw exception text. ## Empty states An empty state is not a blank screen with an apology. It says what belongs here, why it is empty (new, filtered, or failed — three different states, three different messages), and the one action that fills it. ## Permission prompts Ask *at the moment of need*, never at launch. The prompt says what the user gets, not what the app wants. The system string (`NSCameraUsageDescription` etc.) is written by you, not by an engineer at build time — and a denied permission needs a working path, not a dead end. ## The rules - **Every user-visible string goes into the localisation file from the moment it is written.** Retrofitting is far more expensive and is where hardcoded strings survive to ship (`localisation`). - **No placeholder text reaches a build.** `Lorem ipsum`, `TODO`, `Test` in a screenshot is an ASO and a review failure at once. - **One term per concept, product-wide.** A record is not an "item" here and an "entry" there. Keep the list in `docs/14-components.md`. - Numbers, dates, currencies and plurals are formatted by the platform's locale-aware API — never by string concatenation. ## Output Copy lives with the screen that shows it, in `docs/12-flows.md` and `docs/14-components.md`. A state in the inventory with no copy is not specified.