
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeI 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.
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>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>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>For full working examples with Nuxt and Sanity, check out:
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! 🚀
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.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store