Rendering Portable Text with @nuxtjs/sanity - Working Example Needed?
I totally understand your frustration! Rendering Portable Text in Nuxt can be tricky when you're starting out. The good news is there's an official solution that should work smoothly for you.
The Official Approach: @portabletext/vue
For Vue and Nuxt projects, the official Portable Text package is @portabletext/vue. This is maintained by Sanity and is the recommended way to render Portable Text in Vue/Nuxt applications.
1. Install the package:
npm install @portabletext/vue2. Use it in your Nuxt component:
<template>
<div>
<h1>{{ post.title }}</h1>
<PortableText :value="post.body" />
</div>
</template>
<script setup>
import { PortableText } from '@portabletext/vue'
const sanity = useSanity()
const query = `*[_type == "post"][0]{
title,
body
}`
const { data: post } = await useSanityQuery(query)
</script>Customizing Your Portable Text Output
You can customize how different elements render by passing a components prop:
<template>
<PortableText
:value="post.body"
:components="components"
/>
</template>
<script setup>
import { PortableText } from '@portabletext/vue'
const components = {
types: {
image: ({ value }) => {
return h('img', {
src: value.imageUrl,
alt: value.alt || 'Image'
})
}
},
marks: {
link: ({ value, children }) => {
return h('a', {
href: value.href,
target: '_blank',
rel: 'noopener noreferrer'
}, children)
}
},
block: {
h1: ({ children }) => h('h1', { class: 'text-4xl font-bold' }, children),
normal: ({ children }) => h('p', { class: 'mb-4' }, children)
}
}
</script>Working with @nuxtjs/sanity
If you're using the @nuxtjs/sanity module, you can combine it with @portabletext/vue like this:
In your nuxt.config.ts:
export default defineNuxtConfig({
modules: ['@nuxtjs/sanity'],
sanity: {
projectId: 'your-project-id',
dataset: 'production'
}
})In your component:
<template>
<div v-if="post">
<h1>{{ post.title }}</h1>
<PortableText :value="post.body" />
</div>
</template>
<script setup>
import { PortableText } from '@portabletext/vue'
const query = groq`*[_type == "post" && slug.current == $slug][0]{
title,
body
}`
const { data: post } = await useSanityQuery(query, { slug: 'my-post-slug' })
</script>Complete Working Examples
For full working examples with Nuxt and Sanity, check out:
- The official Nuxt quickstart guide - walks through setting up a complete Nuxt + Sanity project
- Introduction to Portable Text - comprehensive guide on working with Portable Text across different frameworks
- Presenting Block Content - official documentation on rendering Portable Text with various serializers
Additional Help
If you run into specific issues, the Sanity Community on Discord has a dedicated Nuxt channel where folks are really helpful with these kinds of questions. You can share your specific code and get targeted help.
The key takeaway: use @portabletext/vue as your Portable Text renderer - it's the official, maintained solution that works great with Nuxt 3 and the @nuxtjs/sanity module. Once you get it working the first time, it becomes much clearer. Good luck with your blog! 🚀
Show original thread3 replies
Sanity – Build the way you think, not the way your CMS thinks
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.