raft-ui
Version:
React UI components for Raft.
181 lines (119 loc) • 7.48 kB
Markdown
---
name: display
description: "Typography and display: the Text family, InlineCode vs CopyableCode vs CodeBlock, Markdown parts, DescriptionList, Avatar, FilePreview vs Files, Kbd, icons."
---
# Text and display
## Contents
- Use typography primitives for styled text
- Text.Sans vs Text.Heading vs Text.Mono
- InlineCode vs CopyableCode vs CodeBlock
- Markdown and DescriptionList
- Avatar
- FilePreview vs file-list parts
- Kbd
- Icons
- Per-component norms
---
## Use typography primitives for styled text
Use the `Text` namespace when standalone copy needs raft-ui typography. Keep native text elements when their semantics and inherited styles are intentional.
**Incorrect:**
```tsx
<p className="text-sm text-gray-500">Last synced 2 minutes ago</p>
```
**Correct:**
```tsx
<Text.Sans size="small">Last synced 2 minutes ago</Text.Sans>
```
---
## Text.Sans vs Text.Heading vs Text.Mono
| Component | For |
| -------------- | ----------------------------------------------------- |
| `Text.Sans` | body copy, labels, and descriptions |
| `Text.Heading` | section and page headings; `level` is `1` through `6` |
| `Text.Mono` | code-like values, metadata, and tabular numbers |
Prefer the namespace used by the canonical compositions. The equivalent named exports `TextSans`, `TextHeading`, and `TextMono` also exist.
**`Text.Sans` sizes** — `large` `body` `small` `caption`.
**`Text.Mono` sizes** — `code` `meta` `eyebrow` `tabular`.
Use `Text.Mono size="tabular"` for numbers that update in place — counts, timers, file sizes, and percentages. Proportional digits can change width and make the surrounding layout jitter.
```tsx
<Text.Mono size="tabular">{unreadCount}</Text.Mono>
```
Use `size="meta"` for timestamps and IDs, `size="eyebrow"` for the small label above a section.
`Text.Heading` `level` selects both the heading element and its recipe size. Pick it from document structure. Use `render` only when the surrounding document requires a different element.
---
## InlineCode vs CopyableCode vs CodeBlock
| | Use |
| -------------- | ------------------------------------------------------- |
| `InlineCode` | a token inside a sentence — a prop name, a flag, a key |
| `CopyableCode` | a single-line command the user is meant to run or paste |
| `CodeBlock` | multi-line code on display |
If the user's next move is to select the text, it should have been `CopyableCode` or `CodeBlock`.
```tsx
<CopyableCodeRoot>
<CopyableCode truncate>{command}</CopyableCode>
<CopyableCodeAction aria-label="Copy install command" />
</CopyableCodeRoot>
```
`CopyableCodeRoot` sizes are `sm` and `md`. Use `truncate` on `CopyableCode` for long single-line commands, and give `CopyableCodeAction` an `aria-label` that says what is being copied. When you omit it, the label swaps between `Copy code` and `Copied code`.
Compose a titled block with `CodeBlockHeader`, `CodeBlockTitle`, `CodeBlockActions`, and `CodeBlockAction` above `CodeBlockBody`. In a block without a header, place `CodeBlockActions` inside `CodeBlockBody`. Render the complete `<pre><code>…</code></pre>` as body content.
---
## Markdown and DescriptionList
Rendered markdown is styled by the `Markdown*` part set. Map paragraphs, headings, lists, links, blockquotes, code, tables, images, task checkboxes, rules, and marks to the matching exported parts. Wrap wide tables in `MarkdownTableScroll`, and compose `MarkdownTable`, `MarkdownTableRow`, `MarkdownHeaderCell`, and `MarkdownCell`.
`DescriptionList` renders term/value pairs. Wrap `DescriptionTerm` and `DescriptionDetails` in `DescriptionItem`, and set `direction="horizontal"` or `direction="vertical"`.
---
## Avatar
```tsx
<Avatar type="human" size="sm">
<AvatarImage src={user.avatarUrl} />
<AvatarFallback>{initials}</AvatarFallback>
</Avatar>
```
- Pass the required `type` and `size` props. **`type` is `agent` or `human`** and changes the treatment.
- Sizes are `3xs` `2xs` `xs` `sm` `md` `lg` `xl`.
- Include `AvatarFallback` whenever you include `AvatarImage`. When `Avatar` has no children, it renders its built-in fallback automatically.
- Use `AvatarGroup` and `AvatarGroupCount` for stacks. Pass the required avatar `size` to `AvatarGroupCount`.
- `AvatarBadge` for a presence dot attached to the avatar. For a standalone state dot elsewhere, use `Status`.
---
## FilePreview vs file-list parts
`FilePreview` renders **one** file as a tile. It has dedicated shapes rather than a type prop:
| Shape | For |
| --------------------- | ------------------ |
| `FilePreviewMedia` | images and video |
| `FilePreviewDocument` | PDFs and documents |
| `FilePreviewCode` | source files |
| `FilePreviewFile` | anything else |
Pick the shape by what the file is. `FilePreviewBadge` labels the format.
The file-list parts render a **list** surface: `FilesPanel`, `FilesViewport`, `FilesList`, and per-row `FileRow`, `FileThumbnail`, `FileContent`, `FileName`, `FileMeta`, `FileMetaItem`, `FileActions`, `FileAction`, `FileRowOpen`, `FileImage`. There is no `Files` root component.
Use `FilePreview` for attachments inside a composer or message; compose the file-list parts for a browsable list.
---
## Kbd
```tsx
<KbdGroup aria-label="Command K">
<Kbd>⌘</Kbd>
<Kbd>K</Kbd>
</KbdGroup>
```
Render one key per `Kbd`. Use `KbdGroup` to apply spacing to a key combination. Add any visible separator as explicit content when the shortcut notation requires one.
Inside menus, use `DropdownMenuShortcut` / `ContextMenuShortcut` instead of `Kbd`; they handle the right alignment within the row.
---
## Icons
Raft-ui's internal recipes and canonical compositions are tuned to Lucide SVGs, but raft-ui does not re-export icons. When application code imports Lucide icons, declare `lucide-react` as a direct application dependency rather than relying on raft-ui's transitive dependency. A consumer may provide another SVG icon set when it preserves the component's expected sizing and stroke treatment.
Let raft-ui components own their icons' default treatment. Buttons, menu items, sidebar items, toasts, and tabs apply recipe-specific sizing and sometimes theme-specific stroke widths. Override those values only when the component's API or a deliberate one-off treatment requires it.
**Incorrect:**
```tsx
<Button size="icon-sm">
<SearchIcon className="size-4 stroke-2" />
</Button>
```
**Correct:**
```tsx
<Button size="icon-sm">
<SearchIcon />
</Button>
```
In your own markup — outside any icon-owning component — size icons explicitly (`className="size-4"`).
---
## Per-component norms
**`Separator`** — use it when a divider needs raft-ui's themed visual contract or orientation behavior. Native `<hr>` remains valid when its semantics and inherited styling are intentional; avoid imitating `Separator` with an ad hoc border div.
**`ScrollArea`** — use when you need styled scrollbars or a scroll region inside a panel. Compose `ScrollAreaViewport` + `ScrollAreaContent` + `ScrollAreaScrollbar` + `ScrollAreaThumb`, and `ScrollAreaCorner` when both axes scroll. Plain `overflow-auto` is fine for full-page scroll; `ScrollArea` is for bounded regions.
**`Badge`** and **`Status`** — see [feedback.md](./feedback.md).