Helpers

Portable Text

Global helper

This module defines a global <SanityContent> component that can turn portable text into HTML. It is a lightweight functional component without an instance.

As of v2, <SanityContent> uses @portabletext/vue for rendering portable text. This means features and properties available to @portabletext/vue also work with <SanityContent>. Please refer to their Usage guide for advanced configuration options.

This render change introduces breaking changes for <SanityContent> v2 components. Refer to the following upgrade guide:
  • To reflect @portabletext/vue's props, blocksvalue and serializerscomponents attribute name changes have been made. The property types remain the same.
  • Custom components now receive their data nested within a props.value object. When defining components, you need to extract your props from this structure using object spreading: {...props.value}. This applies to all component types (blocks, marks, styles).

Example

<template>
  <SanityContent :value="content" />
</template>

Example with custom components

<template>
  <SanityContent :value="content" :components="components" />
</template>

<script setup>
import { defineAsyncComponent, h, resolveComponent } from 'vue'
import CustomBlockComponent from '~/components/CustomBlockComponent.vue'

const components = {
  types: {
    // This is how to access a component registered by `@nuxt/components`
    lazyRegisteredComponent: props => h(resolveComponent('LazyCustomSerializer'), {
      ...props.value,
    }),
    // A directly imported component
    importedComponent: props => h(CustomBlockComponent, {
      ...props.value,
    }),
    // Example of a more complex async component
    dynamicComponent: props => h(defineAsyncComponent({
      loadingComponent: () => 'Loading...',
      loader: () => import('~/other/component.vue'),
    }), {
      ...props.value,
    }),
  },
  marks: {
    // Custom marks handling
    internalLink: props => h('a', { href: props.value.href }, props.text)
  }
}
</script>
If you want to use the same components in multiple places, consider creating your own component (e.g. <MySanityContent>) which wraps SanityContent with your default components. By creating ~/components/MySanityContent.vue you should be able to use this everywhere in your app without importing it.

Advanced Props

The SanityContent component accepts all props from @portabletext/vue:

<template>
  <SanityContent 
    :value="content" 
    :components="components"
    :onMissingComponent="handleMissingComponent"
    :listNestingMode="'html'" 
  />
</template>

<script setup>
const handleMissingComponent = (message, options) => {
  console.warn(`Missing component: ${options.type} (${options.nodeType})`)
}
</script>

Other resources