From 91495947aad91e01c632e23e97d5648817ae3c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89mile=20R=C3=A9?= Date: Tue, 23 Jun 2026 19:05:25 +0200 Subject: [PATCH] Document typography components over raw elements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v2 token guide endorsed raw

/

with hand-applied step classes, which invites token drift across app code. Add a UI guide section establishing that content text flows through kit typography components (Text, Heading, Code) and that raw elements are reserved for kit internals and structural, non-textual nodes. Cross-link it from the typography token section so the two guides stay aligned. Signed-off-by: Émile Ré --- contrib/claude/ui.md | 37 +++++++++++++++++++++++++++++++++++++ contrib/claude/v2-tokens.md | 2 ++ 2 files changed, 39 insertions(+) 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 `

` / `` / `

` / `` 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 +Measures +{description} +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

    +

    Description

    + +// Bad — wrapping a layout container in a typography component +
    …
    +``` + +> Rule of thumb: if a designer would call it "a heading," "body text," "a caption," or "inline code," it is a kit component. If it's a box, a row, or a layout region, it's a raw element styled with `tv`. + ## Skeletons Every meaningful component provides a paired loading UI named `ComponentName` / `ComponentNameSkeleton` (e.g. `Text` / `TextSkeleton`). diff --git a/contrib/claude/v2-tokens.md b/contrib/claude/v2-tokens.md index ae4416b5b..b2d5c7ab8 100644 --- a/contrib/claude/v2-tokens.md +++ b/contrib/claude/v2-tokens.md @@ -208,6 +208,8 @@ Font family is **Inter Variable** (`font-sans`); mono is a system stack (`font-m

    Description

    ``` +> Prefer the kit's `Text` / `Heading` / `Code` components over raw elements with these classes — they encode the step choice once. See [Typography: components over raw text elements](ui.md#typography-components-over-raw-text-elements). + # Radius (`rounded-1` … `rounded-6`) Numbered radius scale (Radix "Medium" set). The static `rounded-none` / `rounded-full` utilities still work; the numeric ramp replaces Tailwind's `rounded-sm/md/lg`.