Markdown
@portabletext/markdown renders Portable Text blocks as Markdown strings. Use it to generate Markdown for static site generators, README files, AI prompts, or any system that consumes Markdown.
Looking to convert Markdown into Portable Text? See the Markdown to Portable Text conversion guide, whose Round-trip behavior section covers what survives a Markdown → Portable Text → Markdown loop.
Install
Section titled “Install”npm i @portabletext/markdownpnpm add @portabletext/markdownyarn add @portabletext/markdownBasic usage
Section titled “Basic usage”portableTextToMarkdown takes an array of Portable Text blocks and returns a Markdown string. Standard block styles, decorators, and links are handled automatically.
import {portableTextToMarkdown} from '@portabletext/markdown'
const markdown = portableTextToMarkdown(blocks)Custom type renderers
Section titled “Custom type renderers”callout, code, horizontal-rule, html, image, and table block objects render as Markdown out of the box. callout, code, html, image, and table fall back to a fenced JSON block when a value doesn’t match the shape its renderer expects (a consumer’s own differently-shaped code type, say); horizontal-rule always renders ---. Register a renderer for other custom types you use, or to override one of the defaults.
portableTextToMarkdown(blocks, { types: { chart: ({value}) => ``, },})Type renderers receive value (the block object), index (position in the array), and isInline (whether the object appears inline or as a block). Return an empty string to skip an element entirely.
portableTextToMarkdown(blocks, { types: { image: ({value, isInline}) => { if (isInline) return '' return `` }, },})Custom block style renderers
Section titled “Custom block style renderers”Override how block styles render by providing a block map. Each renderer receives value (the block) and children (the already-rendered content of the block).
portableTextToMarkdown(blocks, { block: { h1: ({children}) => `# ${children} #`, blockquote: ({children}) => `<blockquote>${children}</blockquote>`, },})Built-in type renderers
Section titled “Built-in type renderers”callout, code, horizontal-rule, html, image, and table are registered by default. The package also exports DefaultBlockquoteObjectRenderer and DefaultListRenderer for the structural container shapes the parser produces when types.blockquote/types.list matchers are registered; those two stay opt-in since the parser only produces that shape when asked to.
import { DefaultBlockquoteObjectRenderer, DefaultListRenderer, portableTextToMarkdown,} from '@portabletext/markdown'
portableTextToMarkdown(blocks, { types: { blockquote: DefaultBlockquoteObjectRenderer, list: DefaultListRenderer, },})Supply your own types.<name> renderer to override any of the defaults.
| Renderer | Expected fields | Output |
|---|---|---|
DefaultCalloutRenderer |
tone, content |
> [!TYPE]\n> content |
DefaultCodeBlockRenderer |
code, language? |
```lang\ncode\n``` |
DefaultHorizontalRuleRenderer |
(none required) | --- |
DefaultHtmlRenderer |
html |
Raw HTML string |
DefaultImageRenderer |
src, alt?, title? |
 |
DefaultTableRenderer |
rows, headerRows? |
Markdown table |
DefaultBlockquoteObjectRenderer |
content |
> content |
DefaultListRenderer |
kind, items |
Markdown list |
Renderer map keys
Section titled “Renderer map keys”| Key | What it renders |
|---|---|
types |
Custom block and inline objects |
marks |
Annotations and decorators |
block |
Block styles (headings, blockquotes, etc.) |
listItem |
List items |
hardBreak |
Line breaks within blocks |
unknownType |
Fallback for unregistered types |
unknownBlockStyle |
Fallback for unregistered block styles |
unknownListItem |
Fallback for unregistered list items |
unknownMark |
Fallback for unregistered marks |
By default, unknown types render as JSON code blocks. Unknown marks, block styles, and list items pass through their children unchanged.
Supported features
Section titled “Supported features”| Feature | PT to Markdown |
|---|---|
| Headings (h1-h6) | ✅ |
| Paragraphs | ✅ |
| Bold | ✅ |
| Italic | ✅ |
| Inline code | ✅ |
| Strikethrough | ✅ |
| Links | ✅ |
| Blockquotes | ✅ |
| Ordered lists | ✅ |
| Unordered lists | ✅ |
| Nested lists | ✅ |
| Code blocks | ✅ |
| Horizontal rules | ✅ |
| Images | ✅ |
| Tables | ✅ |
| HTML blocks | ✅ |
| Callouts | ✅ |
Further reading
Section titled “Further reading”- Markdown to Portable Text for converting Markdown into PT blocks
@portabletext/markdownon GitHub for full API documentation and changelog