2.7 KiB
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 |
|
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)