diff --git a/contrib/claude/ui.md b/contrib/claude/ui.md index 5f4a23772..6979ad5d6 100644 --- a/contrib/claude/ui.md +++ b/contrib/claude/ui.md @@ -307,6 +307,43 @@ Components fall into two categories: **primitives** and **compound** components. If a compound component is purely presentational (no logic), there is no Root — expose only the Shell. +## Typography: components over raw text elements + +Content text — prose, labels, headings, inline code — renders through the kit's typography **components** (`Text`, `Heading`, `Code`, …), not raw `
` / `` / ` ` / `` / ` Description Description` / `
` with hand-applied token classes. A typography component encodes three decisions in one place so app authors don't re-make them on every element:
+
+1. **Tokens** — the numbered type step + color step (`text-3 text-sand-12`, `text-1 text-sand-11`). v2 wipes Tailwind's default type scale (see [`v2-tokens.md`](v2-tokens.md)), so every raw element would otherwise re-pick these.
+2. **Semantics** — the component renders the correct semantic element (a real heading, paragraph, or ``) so the document outline stays tied to the visual hierarchy rather than drifting from it.
+3. **Skeleton pairing** — each primitive has a matching `*Skeleton` (`TextSkeleton`); raw spans have no loading placeholder.
+
+Because these primitives merge the native element's props (see [Props typing](#props-typing)), using `Text` over `span` loses nothing — `id`, `className`, `aria-*`, and handlers still pass through.
+
+### Use a component when the node is typography
+
+```tsx
+// Good — typography flows through kit components
+npm run dev
+```
+
+### Use a raw element only when it isn't typography
+
+Raw `` belong in exactly two places:
+
+- **Inside the kit**, authoring `Text` / `Heading` / `Code` themselves — a primitive *is its own shell*, so its raw element lives there and nowhere else.
+- **Structural, non-textual nodes** — a layout ``, styled with `tv`. These are not typography and must not be wrapped in a typography component.
+
+```tsx
+// Bad — raw heading/body with re-picked tokens scattered across app code
+
Measures
+