# Blocks

An article's body is an ordered array of blocks, each with a `type`. Render the types you know and skip the rest. A type added later is then missing from the page instead of breaking it.

| Type | Fields | |
|---|---|---|
| `heading` | `level: 2 \| 3 \| 4`, `text`, `id` | `id` is an anchor derived from the text, unique within the article; a rewrite that changes the heading changes it. The article title isn't a block. |
| `paragraph` | `content: RichText` | |
| `list` | `ordered`, `items: RichText[]` | |
| `quote` | `content: RichText`, `attribution?` | |
| `code` | `language?`, `code` | Plain text; don't interpret. |
| `image` | `url`, `alt`, `caption?` | On the SEO for SaaS CDN; `alt` is always set. |
| `callout` | `variant: "info" \| "tip" \| "warning"`, `content: RichText` | |
| `cta` | `heading`, `body?`, `buttonLabel`, `buttonHref` | A call to action into your product. |
| `faq` | `items: { question, answer: RichText }[]` | Also in `seo.jsonLd` as FAQPage. |
| `table` | `headers: string[]`, `rows: string[][]` | Plain-text cells. |
| `video` | `provider: "youtube"`, `videoId`, `url`, `title` | A YouTube video taken from the search results for the topic. |

Every block also carries an `id`, unique within the article. Each type has a page with a live render under [Components](/docs/components).

## Rich text

Paragraphs, list items, quotes, callouts and FAQ answers are `RichText`: an array of runs.

| Field | Type | |
|---|---|---|
| `text` | `string` | Plain text. Render it as text, never as HTML. |
| `bold`, `italic`, `code` | `boolean?` | Inline styling. |
| `href` | `string?` | Makes the run a link: `https:` or `http:`, a site path (`/pricing`), or a `#` anchor. Nothing else. |
| `rel` | `string?` | Set on every link to a research source, currently `nofollow ugc noopener`. Pass it to the anchor unchanged. |

```json title="A paragraph citing a source"
{
  "type": "paragraph",
  "content": [
    { "text": "Google describes the process in its " },
    {
      "text": "guide to how Search works",
      "href": "https://developers.google.com/search/docs/fundamentals/how-search-works",
      "rel": "nofollow ugc noopener"
    },
    { "text": "." }
  ]
}
```

## JSON Schema

[https://api.seoforsaas.dev/public/v1/schema/blocks.json](https://api.seoforsaas.dev/public/v1/schema/blocks.json) describes the block array. It's generated from the schema the API validates with, so it always matches what the API returns. The API enforces the link-scheme and `rel` rules.
