:::contentbit
How-to guides

Render documents

Render a validated contentbit document in React, Astro, or plain Markdown.

Renderers consume a validated document. Parse and validate first, then hand the result to the target that matches your app:

import { genericBlocks } from '@contentbit/blocks'
import { assertValidDocument, compileDocument, createBlockRegistry } from '@contentbit/core'

const registry = createBlockRegistry().use(genericBlocks())
const document = assertValidDocument(compileDocument(markdown, registry), 'article.md')

For the design behind this split, see Rendering model.

React

import { ContentBlocks } from '@contentbit/react'

<ContentBlocks
  document={document}
  components={{ comparison: MyComparison }}
  renderMarkdown={(md) => <Markdown source={md} />}
  fallback={MyInvalidBlock}
/>

@contentbit/react renders Markdown segments through renderMarkdown, calls your block components by name, and uses fallback for invalid or unregistered blocks in development surfaces.

For pre-made components, install the shadcn pack. The files land in your app and are yours to edit:

pnpm dlx shadcn@latest add @contentbit/generic-pack

Astro

---
import { ContentBlocks } from '@contentbit/astro/components'
import QuoteBlock from '../blocks/QuoteBlock.astro'
---

<ContentBlocks
  document={document}
  components={{ quote: QuoteBlock }}
  renderMarkdown={renderMarkdown}
  onInvalid="annotated"
/>

Per-block overrides are plain .astro components: validated props arrive as component props, nested content via <slot />, and the raw AST node as the reserved node prop. They also receive ctx, currently { renderMarkdown }, so Markdown strings inside node.data can use the same site pipeline as normal prose. The onInvalid default is annotated, which keeps invalid blocks loud during dev. Full guide: Astro.

For pre-made Astro components:

pnpm dlx shadcn@latest add @contentbit/astro-pack

Plain Markdown fallback

import { renderToMarkdown } from '@contentbit/core'
import { genericMarkdownRenderers } from '@contentbit/blocks'

const md = renderToMarkdown(document, { renderers: genericMarkdownRenderers })

Comparisons become Markdown tables, key metrics become bold-value bullets, tabs become headed sections. Useful for email, exports, search indexing, and any environment without a component runtime. Blocks without a renderer degrade to their raw body, so information is not lost.

Markdown prose

React and Astro renderers both need a Markdown prose function. Wire that once with Plug in your Markdown library, then reuse it for paragraphs between blocks and Markdown bodies inside blocks.

On this page