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

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

> A typographic wrapper that styles raw rendered HTML (CMS/markdown output) with the PDS type scale and rhythm.

## When to use it

**Prose** is the render target for any body content the design system does not compose element-by-element: a blog post, a changelog entry, a docs page, a rich-text CMS field. Because Protocore sites are CMS-driven, this is the seam where editor output meets the type system — the CMS emits plain semantic HTML and `Prose` gives it the house measure, rhythm, and link treatment without the editor needing to know a single class name.

It is server-safe and stateless: render it in a React Server Component, or feed it a string. For content you compose yourself in JSX, reach for **Text**, **Heading**, and **Blockquote** directly instead.

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `className` | `string` | no | — | — |
| `html` | `string` | no | — | A trusted HTML string to render into the scope (e.g. CMS/markdown output). Rendered via `dangerouslySetInnerHTML`, so it MUST already be sanitized by the producer. Mutually exclusive with `children`. |
| `size` | `enum` | no | `md` | Body density: `sm` sets a 14px base with tighter rhythm; `md` (default) is the 16px reading measure. |
| `style` | `CSSProperties` | no | — | — |

## Examples

### Rendering markup

Wrap already-rendered HTML — from a CMS, an MDX pipeline, or markdown — in `Prose`. Every descendant (`h1`–`h6`, `p`, lists, `blockquote`, `code`, `pre`, `a`, `table`, `hr`) inherits the type scale and vertical rhythm from the single scope; the source markup carries no classes of its own.

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

export default function ProseBasics() {
  return (
    <div style={{ maxWidth: "68ch" }}>
      <Prose>
        <h2>Deploying to the edge</h2>
        <p>
          Protocore ships static sites to CloudFront, one distribution per domain. Content is
          driven by a single multi-tenant CMS, so editors never touch a build.
        </p>
        <h3>How a publish flows</h3>
        <ul>
          <li>An editor saves a change in the CMS.</li>
          <li>A webhook triggers the affected site&apos;s static export.</li>
          <li>
            The bundle syncs to S3 and the distribution is invalidated — see the{" "}
            <a href="#pipeline">pipeline notes</a>.
          </li>
        </ul>
        <blockquote>
          Sharp edges, monochrome surfaces, one reserved accent. The rhythm carries the page.
        </blockquote>
        <p>
          Inline <code>tokens.css</code> holds the source of truth, and a <code>pre</code> block
          renders any snippet in the mono family:
        </p>
        <pre>
          <code>{`export const deploy = () => sync(bucket);`}</code>
        </pre>
      </Prose>
    </div>
  );
}
```

### Trusted HTML string

Pass a pre-sanitized HTML string via the `html` prop when the content arrives as a string off the wire. It renders through `dangerouslySetInnerHTML`, so the producer must sanitize it first.

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

// In production this string would arrive already-sanitized from the CMS.
const cmsHtml = `
  <h3>From the CMS</h3>
  <p>This block was authored in a rich-text field and rendered to <strong>plain HTML</strong>.</p>
  <ol>
    <li>Editors write content.</li>
    <li>The field serializes to HTML.</li>
    <li><em>Prose</em> gives it the house type scale.</li>
  </ol>
`;

export default function ProseHtml() {
  return (
    <div style={{ maxWidth: "68ch" }}>
      <Prose html={cmsHtml} />
    </div>
  );
}
```

## Usage

**Do**

- Feed it semantic HTML from your CMS or markdown renderer.
- Sanitize any `html` string upstream before it reaches the prop.
- Use `size="sm"` inside cards and narrow columns.
- Let a parent constrain the line length (a `max-width` around 68ch reads best).

**Don't**

- Pass unsanitized user input to `html`; sanitize at the source.
- Reach for it to lay out app UI; compose Text/Heading/Stack there.
- Add classes to the inner markup; the scope styles bare elements.
- Nest a Prose inside a Prose; one scope owns the whole block.

## Accessibility

**Notes**

- Emits no wrapper semantics beyond a `div`; the heading order and landmarks come from your source HTML, so keep it well-structured.
- Link styling uses an underline plus an accent decoration color, so links are distinguishable without relying on color alone.
- Code blocks scroll horizontally inside their own container so long lines never force the page to scroll.

## Related

`text`, `heading`, `blockquote`, `code-block`

---

© 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/
