PluginBench
Skill
Official
Pass
Audit score 90

portable-text-conversion

sanity-io/agent-toolkit

Convert HTML and Markdown into Portable Text blocks for Sanity content migration and pipelines.

What is portable-text-conversion?

Transforms external rich-text content (HTML, Markdown) into Sanity's Portable Text format for content ingestion and migration. Use this when importing from legacy CMSs, building content pipelines, or programmatically creating Portable Text documents.

  • Convert Markdown to Portable Text using @portabletext/markdown
  • Parse HTML into Portable Text blocks using @portabletext/block-tools
  • Manually construct Portable Text blocks from any data source
  • Handle text styling, marks, annotations, and list structures
  • Support custom block types and nested content
  • Generate unique keys and maintain Portable Text specification compliance

How to install portable-text-conversion

npx skills add https://github.com/sanity-io/agent-toolkit --skill portable-text-conversion
Prerequisites
  • Sanity project setup
  • Node.js environment
  • Understanding of Portable Text structure and blocks
Claude Code
Cursor
Windsurf
Cline

How to use portable-text-conversion

  1. 1.Choose your source format: Markdown, HTML, or manual construction
  2. 2.For Markdown: use markdownToPortableText from @portabletext/markdown
  3. 3.For HTML: use htmlToBlocks from @portabletext/block-tools
  4. 4.For custom sources: manually construct blocks following the Portable Text specification
  5. 5.Ensure all blocks and spans have unique _key values
  6. 6.Map source content to appropriate Portable Text block types (block, image, custom types)
  7. 7.Handle marks and markDefs for text annotations
  8. 8.Test conversion output against Portable Text schema before importing

Use cases

Good for
  • Migrating content from legacy CMS platforms to Sanity
  • Importing HTML or Markdown files into Sanity projects
  • Building automated content pipelines that ingest external sources
  • Converting rich-text formats between different systems
  • Programmatically generating Portable Text documents from APIs or databases
Who it's for
  • Content migration specialists
  • Backend developers building content pipelines
  • Sanity CMS administrators
  • Full-stack developers integrating external content sources

portable-text-conversion FAQ

What's the difference between @sanity/block-tools and @portabletext/block-tools?

@portabletext/block-tools is the current package; @sanity/block-tools is legacy. Use @portabletext/block-tools for new projects—the API is identical.

Do I need to manually add _key to every block and span?

Yes, every block and span requires a unique _key within the array. This is essential for Sanity's content tracking and editing.

Can I convert complex nested HTML structures?

Yes, htmlToBlocks handles nested structures, but custom deserializers may be needed for non-standard HTML or deeply nested content.

What if my source format isn't Markdown or HTML?

Use manual construction to build Portable Text blocks programmatically from any data source (APIs, databases, custom formats).

How do I handle images and other non-text blocks?

Include image blocks with asset references, or use custom block types. Map source media to Sanity asset references during conversion.

Full instructions (SKILL.md)

Source of truth, from sanity-io/agent-toolkit.


name: portable-text-conversion description: Convert HTML and Markdown content into Portable Text blocks for Sanity. Use when migrating content from legacy CMSs, importing HTML or Markdown into Sanity, building content pipelines that ingest external content, converting rich text between formats, or programmatically creating Portable Text documents. Covers @portabletext/markdown (markdownToPortableText), @portabletext/block-tools (htmlToBlocks), custom deserializers, and the Portable Text specification for manual block construction. license: MIT metadata: author: sanity version: "1.0.0"

Portable Text Conversion

Convert external content (HTML, Markdown) into Portable Text for Sanity. Three main approaches:

  1. markdownToPortableText — Convert Markdown directly using @portabletext/markdown (recommended for Markdown)
  2. htmlToBlocks — Parse HTML into PT blocks using @portabletext/block-tools (for HTML migration)
  3. Manual construction — Build PT blocks directly from any source (APIs, databases, etc.)

Portable Text Specification

Understand the target format before converting. PT is an array of blocks:

[
  {
    "_type": "block",
    "_key": "abc123",
    "style": "normal",
    "children": [
      {"_type": "span", "_key": "def456", "text": "Hello ", "marks": []},
      {"_type": "span", "_key": "ghi789", "text": "world", "marks": ["strong"]}
    ],
    "markDefs": []
  },
  {
    "_type": "block",
    "_key": "jkl012",
    "style": "h2",
    "children": [
      {"_type": "span", "_key": "mno345", "text": "A heading", "marks": []}
    ],
    "markDefs": []
  },
  {
    "_type": "image",
    "_key": "pqr678",
    "asset": {"_type": "reference", "_ref": "image-abc-200x200-png"}
  }
]

Key rules:

  • Every block and span needs _key (unique within the array)
  • _type: "block" is for text blocks; custom types use their own _type
  • markDefs holds annotation data; marks on spans reference markDefs[*]._key or are decorator strings
  • Lists use listItem ("bullet" | "number") and level (1, 2, 3...) on regular blocks

Conversion Rules

Read the rule file matching your source format:

  • Markdown → Portable Text: rules/markdown-to-pt.md — @portabletext/markdown with markdownToPortableText (recommended)
  • HTML → Portable Text: rules/html-to-pt.md — @portabletext/block-tools with htmlToBlocks
  • Manual PT Construction: rules/manual-construction.md — build blocks programmatically from any source

Note: @sanity/block-tools is the legacy package name. Always use @portabletext/block-tools for new projects. The API is the same.