|
| 1 | +--- |
| 2 | +description: UI copy conventions — no default subtitles or helper text under headings, labels, cards, or settings |
| 3 | +globs: ["apps/sim/**/*.tsx"] |
| 4 | +--- |
| 5 | +# UI Copy |
| 6 | + |
| 7 | +**Do not add subtitles, helper text, or descriptive copy beneath headings, labels, cards, or settings by default.** Prefer one concise, self-explanatory heading or label. Only add supporting copy when the user explicitly asks for it, or when it is necessary to prevent misunderstanding or error — and never use it to restate the heading. |
| 8 | + |
| 9 | +This applies to product surfaces: settings rows, modals, panels, cards, list rows, empty states, form fields, and section headers. Marketing surfaces (`app/(landing)`, docs) are governed by `constitution.mdc` instead. |
| 10 | + |
| 11 | +**Carve-out — settings section metadata.** `SettingsNavigationItem.description` in `components/settings/navigation.ts` stays required, and `SettingsPanel` keeps rendering it as the page subtitle. Settings sections are reached through a nav list where the description is the only thing distinguishing adjacent sections. Everything else on a settings page — inline `<p>` blurbs under section headings, field hints, modal bodies, row subtitles — follows the default rule above. |
| 12 | + |
| 13 | +## The default is no description |
| 14 | + |
| 15 | +```tsx |
| 16 | +// ✗ Bad — the subtitle restates the heading |
| 17 | +<h3>API Keys</h3> |
| 18 | +<p className='text-[var(--text-muted)] text-caption'>Manage your API keys.</p> |
| 19 | + |
| 20 | +// ✗ Bad — decorative filler under a field label |
| 21 | +<ChipModalField title='Workspace name' hint='The name of your workspace.' /> |
| 22 | + |
| 23 | +// ✓ Good — the label carries the whole meaning |
| 24 | +<h3>API Keys</h3> |
| 25 | +<ChipModalField title='Workspace name' /> |
| 26 | +``` |
| 27 | + |
| 28 | +If a heading needs a subtitle to be understood, the heading is wrong. Fix the heading — don't append a second line. |
| 29 | + |
| 30 | +## When supporting copy earns its place |
| 31 | + |
| 32 | +Keep (or add) a description only when it carries information the label cannot, and its absence would cause a mistake: |
| 33 | + |
| 34 | +- **Irreversible or destructive consequences** — "Deleting this workspace removes every workflow and log. This cannot be undone." |
| 35 | +- **A non-obvious format, unit, or bound** — "Comma-separated. Max 50 domains.", "Cost per 1M input tokens." |
| 36 | +- **A security or access implication** — "This key is shown once and grants full workspace access." |
| 37 | +- **A state the user cannot otherwise see** — "Inherited from your organization's policy." |
| 38 | +- **Instructional copy that advances a flow** — "We sent a 6-digit code to you@example.com." |
| 39 | + |
| 40 | +Everything else — restatements, "Manage your X", "Configure your Y", feature blurbs, encouragement — gets deleted. |
| 41 | + |
| 42 | +## Component APIs |
| 43 | + |
| 44 | +Description/hint slots on shared components are **optional**, never required, and must reserve no layout space when omitted. A component that forces every consumer to supply a subtitle forces every consumer to violate this rule. When adding a new shared component, ship it without a description slot and add one only once a real caller meets the bar above. |
0 commit comments