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.

rulessvelte.md

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

Serialize Portable Text to Svelte

Use @portabletext/svelte (requires Svelte 5+) to render PT in Svelte/SvelteKit.

npm install @portabletext/svelte

Basic Usage

<script>
  import {PortableText} from '@portabletext/svelte'

  let {value} = $props()
</script>

<PortableText {value} components={components} />

Custom Components

Svelte components receive a portableText prop with value, global, and indexInParent. Child content is passed via Svelte snippets.

Block Styles

<!-- Heading.svelte -->
<script>
  let {portableText, children} = $props()
  const {value} = portableText
</script>

{#if value.style === 'h1'}
  <h1 class="text-4xl font-bold">{@render children()}</h1>
{:else if value.style === 'h2'}
  <h2 class="text-3xl font-semibold">{@render children()}</h2>
{:else}
  <p>{@render children()}</p>
{/if}

Custom Types

<!-- ImageBlock.svelte -->
<script>
  let {portableText} = $props()
  const {value} = portableText
</script>

<figure>
  <img src={urlFor(value).width(800).url()} alt={value.alt || ''} />
  {#if value.caption}
    <figcaption>{value.caption}</figcaption>
  {/if}
</figure>

Mark Components (Annotations)

<!-- Link.svelte -->
<script>
  let {portableText, children} = $props()
  const {value} = portableText
  const href = value?.href || ''
</script>

<a {href} rel={href.startsWith('/') ? undefined : 'noreferrer noopener'}>
  {@render children()}
</a>

Assembling Components

<script>
  import {PortableText} from '@portabletext/svelte'
  import ImageBlock from './ImageBlock.svelte'
  import CodeBlock from './CodeBlock.svelte'
  import Link from './Link.svelte'

  let {value} = $props()

  const components = {
    types: {
      image: ImageBlock,
      code: CodeBlock,
    },
    marks: {
      link: Link,
    },
    block: {
      h1: ({children}) => `<h1>${children}</h1>`, // or use a component
    },
  }
</script>

<PortableText {value} {components} />

Passing Context

Pass external data to all components via context:

<PortableText
  {value}
  {components}
  context={{dataset: 'production', footnotes}}
/>

Access in components via portableText.global.context.

Plain Text Extraction

import {toPlainText} from '@portabletext/svelte'

const text = toPlainText(blocks)

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.