All skills
sanity-io avatar

/portable-text-serialization

@a11c399 official
by Sanitysanity-io/agent-toolkit187 stars
30

Render and serialize Portable Text to React, Svelte, Vue, Astro, HTML, Markdown, and plain text. Use when implementing Portable Text rendering in any frontend framework, building custom serializers for non-standard block types, converting Portable Text to HTML strings server-side, converting Portable Text to Markdown, extracting plain text from Portable Text, or troubleshooting rendering issues with marks, blocks, lists, or custom types.

Use this Skill: https://skilld.dev/gh/sanity-io/agent-toolkit/portable-text-serialization

This session only. Nothing lands on disk.

ruleshtml.md

≈793 tokens on demand. Your agent reads this file only when SKILL.md points to it.

Serialize Portable Text to HTML

Use @portabletext/to-html for server-side HTML string generation — useful for RSS feeds, emails, static rendering, or any non-framework context.

npm install @portabletext/to-html

Basic Usage

import {toHTML} from '@portabletext/to-html'

const html = toHTML(portableTextBlocks, {components})

⚠️ Security: Escape HTML

Unlike framework renderers, toHTML returns raw strings. You must sanitize output.

Use htm + vhtml for safe templating, or the built-in escapeHTML utility:

import {toHTML, escapeHTML, uriLooksSafe} from '@portabletext/to-html'
import htm from 'htm'
import vhtml from 'vhtml'

const h = htm.bind(vhtml)

Custom Components

Components are functions returning HTML strings:

const components = {
  types: {
    image: ({value}) => {
      return `<figure>
        <img src="${escapeHTML(value.url)}" alt="${escapeHTML(value.alt || '')}" />
        ${value.caption ? `<figcaption>${escapeHTML(value.caption)}</figcaption>` : ''}
      </figure>`
    },
    code: ({value}) => {
      return `<pre data-language="${escapeHTML(value.language)}"><code>${escapeHTML(value.code)}</code></pre>`
    },
  },

  marks: {
    link: ({children, value}) => {
      const href = value?.href || ''
      if (!uriLooksSafe(href)) return children
      const rel = href.startsWith('/') ? '' : ' rel="noreferrer noopener"'
      return `<a href="${escapeHTML(href)}"${rel}>${children}</a>`
    },
    strong: ({children}) => `<strong>${children}</strong>`,
    em: ({children}) => `<em>${children}</em>`,
    highlight: ({children}) => `<mark>${children}</mark>`,
  },

  block: {
    h1: ({children}) => `<h1>${children}</h1>`,
    h2: ({children}) => `<h2>${children}</h2>`,
    blockquote: ({children}) => `<blockquote>${children}</blockquote>`,
    normal: ({children}) => `<p>${children}</p>`,
  },

  list: {
    bullet: ({children}) => `<ul>${children}</ul>`,
    number: ({children}) => `<ol>${children}</ol>`,
  },

  listItem: {
    bullet: ({children}) => `<li>${children}</li>`,
  },
}

With htm/vhtml (Auto-Escaped)

Using htm + vhtml auto-escapes attribute values, preventing XSS from user content that could break out of attributes in raw template literals:

const components = {
  types: {
    image: ({value}) => h`<img src=${value.url} alt=${value.alt || ''} />`,
  },
  marks: {
    link: ({children, value}) => {
      if (!uriLooksSafe(value?.href || '')) return children
      return h`<a href=${value.href}>${children}</a>`
    },
  },
}

Use Cases

Use Case Why toHTML
RSS/Atom feeds Need raw HTML string
Email templates No framework runtime
Static site generation Pre-render at build time
API responses Return HTML from endpoints
PDF generation Feed HTML to PDF libraries

Reference

Source: SKILL.md on GitHub

No alerts16d4 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill provides comprehensive reference guides, code patterns, and best practices for serializing and rendering Portable Text across several frontend frameworks (React, Svelte, Vue, Astro, HTML, Markdown). It implements secure coding recommendations, explicitly advising developers on how to prevent Cross-Site Scripting (XSS) vulnerabilities by sanitizing data and escaping HTML during server-side string generation.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at a11c399. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 weeks ago.

Activeupdated 8 months ago
metadata
{
  "author": "sanity",
  "version": "1.0.0"
}
  • React
  • Vue
  • portable-text
  • sanity
  • svelte
  • astro
  • serialization
  • rendering
  • markdown
  • html

README badge

README badge for sanity-io/agent-toolkit/portable-text-serialization

Render Portable Text to React, Svelte, Vue, Astro, HTML, Markdown, and plain text using the @portabletext library family. Maps PT node types (blocks, marks, custom types) to framework-specific components, with rules and patterns for each target framework and guidance on custom serializers for non-standard block types.

Generated from the current SKILL.md.

Does this skill support rendering Portable Text in React, Vue, Svelte, and Astro?
Yes. The skill covers @portabletext/react, @portabletext/vue, @portabletext/svelte, and astro-portabletext, each following the same component-mapping pattern.
Can I convert Portable Text to HTML or Markdown server-side?
Yes. Use @portabletext/to-html for server-side HTML strings or @portabletext/markdown to convert to Markdown format.
How do I render custom block types like images or code blocks?
Custom types require explicit component mappings in the components object — they will not render by default. Map each custom _type to a renderer that receives the block's value as props.
Does this skill help with plain text extraction?
Yes. Use @portabletext/toolkit to extract plain text from Portable Text content.
What if my framework or target (React Native, Solid, PHP) isn't listed in the rules?
The skill documents the core component-mapping pattern used by all serializers and lists community packages for React Native, Solid, PHP, Python, and other languages on portabletext.org, though dedicated rule files are only provided for React, Vue, Svelte, Astro, HTML, and Markdown.

Generated from the current SKILL.md. These answers refresh after source changes.