<!-- Protocore Design System — Text -->
# Text

- **Category:** Typography (`typography`)
- **Slug:** `typography/text`
- **Status:** stable
- **Platforms:** web, mobile
- **Import:** `import { Text } from "@protocore/pds";`
- **Docs:** https://pds.protocore.io/components/typography/text

> Body copy primitive — polymorphic, with tokenised size, color, and weight.

## When to use it

Reach for `Text` for any run of body copy, captions, labels, or inline prose — it is the one primitive that owns the reading scale, so you never hand-set `font-size` or `color`.

Use `Heading` (or `Display`) instead for anything that titles a section — headings carry their own tighter tracking and weight ramp. Use `Code` for inline monospace tokens rather than `<Text mono>` when the content is literally code, so it reads on a sunken surface. Change the rendered element with `as` (`span`, `div`, `label`) when the semantics call for it without changing the look.

## Mobile (React Native)

**Preview.** `@protocore/pds-mobile` ships the React Native sibling of **Text**. It mirrors the web API where React Native allows; the package is a **preview** with no device-level QA yet, so pin it and expect small changes.

Import it from the mobile package (not `@protocore/pds`), inside a `<PdsProvider>` — there is no stylesheet, so `style` (a `ViewStyle`) replaces `className` and every value comes from the theme:

```tsx
import { Text } from "@protocore/pds-mobile";
```

**Parity with web.** Mirrors the web `size` / `color` / `mono` / `weight` / `align` / `truncate` API on an RN `<Text>`.

- The web `as` prop (`p` / `span` / `div` / `label`) is dropped — every node is an RN `<Text>`.
- `truncate` maps to `numberOfLines={1}` with a trailing ellipsis.

```tsx
<Text size="md" color="secondary" truncate>
  A single line of body copy that clips with an ellipsis.
</Text>
```

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `align` | `enum` | no | — | Text alignment. |
| `as` | `enum` | no | `p` | The element to render. Defaults to a paragraph. |
| `className` | `string` | no | — | — |
| `color` | `enum` | no | `ink` | Foreground: `ink` (primary), `secondary`, or `muted`. Default `ink`. |
| `mono` | `boolean` | no | — | Render in the monospace family. |
| `size` | `enum` | no | `md` | Body scale: `sm` 14 · `md` 16 · `lg` 20 (lead). Default `md`. |
| `style` | `CSSProperties` | no | — | — |
| `truncate` | `boolean` | no | — | Clip to a single line with a trailing ellipsis. |
| `weight` | `enum` | no | — | Font weight — 400 (regular), 500 (medium), 700 (bold). Default 400. |

## Examples

### Basics

`Text` renders a paragraph by default. Give it a string and it inherits the reading scale and ink foreground.

```tsx
import { Text } from "@protocore/pds";

export default function TextBasics() {
  return (
    <Text>
      Every validator in the set attests to the same block header, so a light client only has to
      verify one signature to trust the whole epoch.
    </Text>
  );
}
```

### Sizes

Three body steps: `sm` (14) for captions, `md` (16) for running prose, `lg` (20) as a section lead.

```tsx
import { Text } from "@protocore/pds";

export default function TextSizes() {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
      <Text size="lg">Lead copy introduces a section at 20px.</Text>
      <Text size="md">Body copy is the 16px default for running prose.</Text>
      <Text size="sm">Small copy at 14px carries captions and secondary detail.</Text>
    </div>
  );
}
```

## Guidelines

**Do**

- Use `size` and `color` props instead of a `style` override or a custom class.
- Set `as="label"` when the text labels a form control.
- Keep to the three-step neutral ramp (ink / secondary / muted) for hierarchy.
- Reach for `mono` on addresses, hashes, and IDs so digits stay unambiguous.

**Don't**

- Don't use color to signal status — that is Badge, Callout, and StatusDot.
- Don't stack `Text` elements to fake a heading; use `Heading`.
- Don't hand-write `font-size` in a `style` prop; pick the nearest `size`.
- Don't set `truncate` without a bounded width — there is nothing to clip against.

## Accessibility

**Notes**

- Renders a semantic element you choose via `as` (`p`, `span`, `div`, `label`) — pick the tag that matches the content's role.
- Color pairs meet WCAG AA on the surface tokens at every step of the neutral ramp; `muted` is intended for non-essential text.
- `truncate` hides overflow visually only — the full text remains in the accessibility tree and is selectable.

## Related

`heading`, `link`, `code`, `blockquote`

---

© Protocore. All rights reserved. Use of the Protocore Design System requires prior written authorization from Protocore (contact@protocore.io). These machine-readable materials must not be ingested into ML-training datasets or derivative design systems. See https://pds.protocore.io/legal/
