AhaSlides Design
v0.52.0React · Vue · Lit

Patterns · composition guide

UX writing pattern

The WORDS in every product surface — sentence-case casing, one canonical label, and specific / actionable / blameless error-empty-feedback microcopy — applied to the labels and copy the existing components render.

◆ generated from guidelines/ux-writing.json + parts/ux-writing.guide.md — do not edit by hand

UX writing is cross-cutting: every button label, slide-type name, heading, tooltip, empty state, and error message across the editor, dashboard, settings, and audience UIs is governed by the same casing and microcopy rules. This pattern ships NO new component — it documents WHAT the copy says and HOW it's cased, leaning on the existing Button label, Icon, and the --aha-color* feedback tokens. The narrative 'why', the worked before/after library, and the brand voice live in the aha-design-ux-writing skill and aha-branding; this artifact carries only the enforceable wording rules and links each back by ref.

Based on

The rationale, worked examples, and the full assertion set live in the design skill — this pattern distils the enforceable subset and links each rule back to it.

build aha-design:aha-design-ux-writing judge aha-design:aha-design-ux-writing-judge

Choose the surface

SurfaceUse forExample
Label / CTA / menu / tabthe name of an action or destination — sentence case, one canonical form reused everywhereView report, Create presentation, Multiple choice
Heading / dialog titlesection and dialog titles — sentence case; a title carries the OUTCOMEWe couldn't open your presentation
Empty statesuccess-but-no-data — encouraging copy + a primary create action, never an apologyNo presentations yet. Create your first one.
Error / load-failure messagea recoverable problem — name the object, give the next step, expose the recovery controlCouldn't load some presentations. Check your connection and try again.

Composed of

What a compliant ux writing surface reuses from this design system — the pattern's link into the component graph.

ReusesKindForIn DS?
buttoncomponentaction/CTA labels the rule cases (sentence case, canonical form) and the in-message recovery control (Retry/Reload/Log in again)available
iconcomponentthe glyph beside a message is functional only; the words, not the glyph, carry the outcomeavailable
--aha-color-errortokena destructive/data-loss or fatal failure message binds its emphasis to the error role — wording severity matches the colour, never a hardcoded redavailable
--aha-color-warningtokena transient retryable hiccup reads as warning/info tone, not a blaring error — the word severity matches a calmer tokenavailable
alertcomponentrecovery-required copy lives in an inline Alert that survives, not an auto-dismissing toast — the shared DS V3 Alert, never a bare AntD Alertmissing
toastcomponenttransient, no-recovery-needed confirmations only; recovery copy must not live here alonemissing
empty-statecomponentthe success-no-data shell whose copy is encouraging + a primary create action, kept distinct from a failuremissing
error-pagecomponentthe full-page failure whose headline names the object + outcome and offers a next stepmissing
⚠︎ 4 referenced components not yet in the DS — alert, toast, empty-state, error-page. composedOf marks 4 components this pattern's copy lives inside that the DS does not yet ship (alert, toast, empty-state, error-page). Per the charter, a pattern that leans on a missing component is a signal to add it HERE — this is the pattern surfacing the component roadmap for the surfaces that host product copy.

Rules

The shippable checklist — each rule traces to an assertion in aha-design:aha-design-ux-writing.

RuleSkill assertion
Sentence case is the house default for ALL product UI text — labels, CTAs, menu/tab/nav items, slide-type and interactive-component names, headings, tooltips, helper text, dialog titles, empty states, and messages. Capitalize the first letter only; keep proper nouns, brand names, and acronyms as-is. 'View report' not 'View Report'; 'Multiple choice' / 'Word cloud' / 'Open-ended' / 'Spinner wheel' / 'Q&A' not Title Case.UXW-1
Pick ONE canonical cased form per label and use it in every place it appears — button, menu, tooltip, analytics label. Resolve AI drift (card says 'View Report', menu says 'View report') to the sentence-case 'View report'; never ship both forms.UXW-1
The styled all-caps eyebrow / overline / chip label (the 'capitalized' typography role, owned by aha-design-typography) is intentionally uppercased — it is a deliberate style, not a casing mistake. Don't 'fix' it to sentence case, and don't cite it to justify Title Case elsewhere.UXW-1
A message names the OUTCOME (what happened, always), adds the CAUSE only when it changes what the user does, always states the NEXT step for anything recoverable, and exposes the ACTION when a one-tap recovery exists. Title = the OUTCOME; body = the NEXT step — never inverted.UXW-2 UXW-3 UXW-7
Name the specific object and what happened — a concrete count over 'some'. 'Couldn't load some presentations.' not 'Some items could not be loaded.' Never ship a standalone 'Something went wrong', 'An error occurred', 'Oops', 'Unexpected error', 'Some items could not be loaded', or bare 'Failed'.UXW-2
Any message about a recoverable problem must tell the user what to do now AND expose the recovery as a real control when a one-tap recovery exists (Retry, Reload, Log in again, Go back, Contact support). A message with an outcome but no next step is a dead-end.UXW-3
Be blameless, jargon-free, and front-loaded. Don't blame the user ('That file type isn't supported — try a PNG or JPG', not 'You entered an invalid file'). Keep raw codes / stack traces / HTTP status out of the headline — tuck any code into secondary detail. Lead with the user's goal, not the system's failure.UXW-4
Match wording severity to real impact. A transient, retryable hiccup is a calm info/warning with 'Try again', not a blaring red 'Error' — over-alarming trains users to ignore real errors. A destructive or data-loss outcome states the stakes plainly ('This permanently deletes 12 responses.') without crying wolf or burying the lede.UXW-5
An empty state (success, no data) is encouraging with a primary next action ('No presentations yet. Create your first one.') — never an apology or a red alarm. A load failure follows be-specific + never-dead-end (name it, offer Retry) and is never disguised as emptiness, which would hide the Retry the user needs.UXW-6
Recovery-required copy must not live only in an auto-dismissing toast — it belongs in an inline Alert or on the page so the words survive. When a message has a title + body, the title carries the outcome and the body the next step (a shapeless single-string message isn't penalised on shape — its vagueness is a be-specific problem).UXW-7

Composition code

Doc-only — this pattern ships no wrapper from this repo. Doc-only pattern — ships no composition wrapper or primitive from this repo. It governs the WORDS inside components that already exist or are backlogged; it owns no code surface of its own. The feedback/empty/error COMPONENTS that host this copy (Alert, toast, ErrorPage, Empty) are owned by aha-design-feedback and aha-design-shared-components; the type SCALE and the all-caps label role by aha-design-typography; the brand VOICE by aha-branding. If a copy-linting helper ever graduates into this DS, add a reuse block and it is gated like a composite.

Guide

UX writing — composition guide

Distilled from aha-design-ux-writing. The skill holds the full rationale, the worked before/after library (references/patterns.md), and all UXW-x assertions; this guide is the shippable checklist. The DS now OWNS this build ruleset — the judge and evals stay in the skill. When the two ever disagree, the skill wins and this file is regenerated.

UX writing is the most cross-cutting surface in the product: the same words and casing appear on a button, a menu item, a tooltip, an empty state, and an error message, across the editor, dashboard, settings, and audience UIs. This pattern adds no new control — it reuses the Button label, the functional Icon, and the --aha-color* feedback tokens, and defines the wording conventions that keep every string reading as one product. It owns what the copy says and how it's cased — not how the surface looks (the component skills) and not the brand voice it's said in (aha-branding).

Pick the surface first

SurfaceUse for
Label / CTA / menu / tabThe name of an action or destination — sentence case, one canonical form reused everywhere
Heading / dialog titleSection and dialog titles — sentence case; the title carries the OUTCOME
Empty stateSuccess-but-no-data — encouraging copy + a primary create action, never an apology
Error / load-failure messageA recoverable problem — name the object, give the next step, expose the recovery control

Casing — sentence case is the house default · UXW-1

Sentence case is the default for all AhaSlides product UI text: button & CTA labels, menu / tab / nav items, slide-type and interactive-component names, section headings, tooltips and helper text, dialog titles, empty states, and message copy.

  • Capitalize the first letter only. Keep proper nouns, brand names, and acronyms as-is.
  • "View report" ❌ "View Report" · "VIEW REPORT" · "view report"
  • Slide-type & interactive-component names are sentence case too:
  • ✅ "Multiple choice" · "Word cloud" · "Open-ended" · "Spinner wheel" · "Brainstorm" · "Rating scale"
  • ✅ acronyms/brand kept: "Q&A" · "AI slide" · "AhaSlides"
  • ❌ "Multiple Choice" · "Word Cloud" · "Open-Ended" · "Spinner Wheel"
  • One canonical form, everywhere. Pick one cased form for a label and use it in every place it

appears — button, menu, tooltip, analytics label. AI-generated UI drifts ("View Report" on the card, "View report" in the menu); the canonical answer is sentence case "View report" — never ship both.

The one exception — a typography role, not a violation. The styled all-caps eyebrow /

overline / chip label (the capitalized role) is intentionally uppercased and is owned by aha-design-typography. It is a deliberate style, not a casing mistake — don't "fix" it to sentence case, and don't cite it to justify Title Case elsewhere.

Errors, empty states & feedback microcopy

The anatomy of a good message

PartWhat it isWhen
OUTCOMEwhat happened, in the user's termsalways
CAUSEwhy, in plain languagewhen it helps the user act
NEXTwhat to do nowalways, for anything recoverable
ACTIONthe button/link that does the NEXTwhenever a one-tap recovery exists
  • Title = the OUTCOME. Body = the NEXT step. Not the reverse.
  • Drop CAUSE when it's noise ("a network request failed") but keep it when it changes what the user

does ("You're offline", "That file is over 50 MB").

  • A message with an OUTCOME but no NEXT is a dead-end — the "*Error? so what now?*" reaction.

Be specific — name the object and what happened · UXW-2

  • ❌ "Some items could not be loaded." → ✅ "Couldn't load some presentations."
  • ❌ "Something went wrong." / "An error occurred." / "Oops!" → name the object + verb.
  • Prefer a concrete count ("3 presentations didn't load") over "some".
  • Banned as a standalone message: *Something went wrong · An error occurred · Oops ·

Unexpected error · Some items could not be loaded · Failed.*

Never dead-end — always give the next step, and the action if one exists · UXW-3

Any message about a recoverable problem must tell the user what to do now and expose the recovery as a real control when a one-tap recovery exists (Retry, Reload, Log in again, Go back, Contact support). The recovery lives in the message, not only in a toast that vanishes.

Human, blameless, jargon-free · UXW-4

  • Don't blame the user. ❌ "You entered an invalid file." → ✅ "That file type isn't

supported — try a PNG or JPG."

  • No raw codes / stack / HTTP status as the headline — tuck any code into secondary detail.
  • Lead with the user's goal, not the system's failure. ❌ "An exception was thrown" →

✅ "We couldn't open your presentation."

Match severity to reality · UXW-5

  • A transient, retryable hiccup is an info/warning with a calm "Try again", not a blaring red

"Error" — over-alarming trains users to ignore real errors.

  • A destructive or data-loss outcome states the stakes plainly ("This permanently deletes 12

responses."). Don't cry wolf; don't bury the lede.

An empty state is not an error · UXW-6

  • Empty (success, no data): encouraging + a primary next action. ✅ "No presentations yet.

Create your first one." Never an apology, never a red alarm.

  • Failure (couldn't load): follow UXW-2/3 — name it, offer Retry. Never disguise a failure as

emptiness ("No presentations" when the fetch errored hides the Retry the user needs).

Put the message where it survives — right home & shape · UXW-7

  • (a) Survives. Recovery-required copy must not live only in an auto-dismissing toast; it

belongs in an inline Alert or on the page. (Surface mechanics owned by aha-design-feedback; this is about not stranding the *words*.)

  • (b) Shape (only when there's a title + body). Title carries the outcome; body the next step —

not inverted. A shapeless single-string message is fine here — its vagueness is a UXW-2 problem, not a UXW-7 one.

Worked example

❌ ⚠️ Some items could not be loaded. → ✅ ⓘ Some presentations didn't load. Check your connection and try again. → [ Try again ]

Vague object → named (UXW-2); dead-end → next step + Retry (UXW-3); calm retryable tone, not a fatal red error (UXW-5).

Universal principles (every string)

Applied by every area above; the areas make them concrete.

  • Consistent — one canonical form per label/term, used everywhere.
  • Specific — name the real object; no vague placeholders.
  • Actionable — tell the user what to do next; labels name the action.
  • Human & plain — blameless, jargon-free, front-loaded.

Areas still to fill

The skill is deliberately incomplete — these areas are owned there but not yet written. Until they are, apply the universal principles above; each lands here with its own rule + ref as it's written.

  • Action-label style — verb-first, concise button/CTA labels ("Create presentation", not

"Presentation creation"); primary vs secondary phrasing.

  • Terminology & glossary — one word per concept across the product (presentation vs deck vs

slideshow); the canonical AhaSlides term list.

  • Tooltips & helper text — when to add, length, imperative vs descriptive.
  • Onboarding & first-run copy — empty-first-run states, coach marks, checklists.
  • Confirmation & consent copy — the words in destructive/consequential dialogs.

*Full detail, the before/after library, and the stubbed areas live in the aha-design-ux-writing

skill. Self-check any copy with aha-design-ux-writing-judge and fix every FAIL before shipping. Stay in your lane: the surface LOOK is aha-design-feedback / aha-design-shared-components, the type SCALE is aha-design-typography, and the brand VOICE is aha-branding:aha-branding-tone-voice.*