Files
theater-ziefen-website/.agents/skills/portable-text-serialization/rules/svelte.md
T
johannes.gasser 57af0b8386
Build and Deploy / build-and-deploy (push) Successful in 2m53s
add skills
2026-05-18 08:39:42 +02:00

2.7 KiB

title, description, tags
title description tags
Serialize Portable Text to Svelte Render Portable Text in Svelte 5 and SvelteKit using @portabletext/svelte
portable-text
svelte
sveltekit
serialization
rendering

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