Rendering Portable Text with @nuxtjs/sanity - Working Example Needed?

3 replies
Last updated: Apr 5, 2021
Hi all, I'm a beginner developer here trying to create my first blog on Sanity using Nuxt. I am having a horrific time trying to render body text using the Portable text helper for the npm package @nuxtjs/sanity. Is there a full working example somewhere someone can point me to? I would be tremendously grateful and indebted to this community, thank you so much.
AI Update

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/vue

2. 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:

  1. The official Nuxt quickstart guide - walks through setting up a complete Nuxt + Sanity project
  2. Introduction to Portable Text - comprehensive guide on working with Portable Text across different frameworks
  3. 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 thread
3 replies
Hi and welcome, Michael. Have you taken a look at the Nuxt event template ?
You can install sanity-blocks-vue-component (https://github.com/rdunk/sanity-blocks-vue-component ) then in your nuxt.config.js put in the plugin like so
plugins: [
    "@/plugins/sanity-blocks.js"
  ],
Then in your component you
import sanity from "../../sanityClient" in the script. Then you can use the block component:
<block-content :blocks="child" v-for="child in missionFirstParagraph" :key="child._id" /> 
In this example,
missionFirstParagraph is the potable text that I'm pulling from sanity that I want to display in paragraph form.
I found this site to be helpful
https://developers.cloudflare.com/pages/tutorials/build-a-blog-using-nuxt-and-sanity
Also there is a Nuxt channel in here that you should search for. Sometimes questions in Help get lost among all the different stuff, but in the Nuxt channel I've found people are really quick to respond and really helpful.
Ok thank you for your help! I didn't realize there was a Nuxt channel. I was able to use the cloudflare tutorial previously but that uses the sanity-blocks-vue-component and I was looking for a way to do it with just with @nuxtjs/sanity . Also the cloudflare tutorial and the nuxt events template use version 0.1.0 of sanity-blocks-vue-compondent and I was trying to implement the 1.0 version which has breaking changes I believe. Regardless though, I will stick with what works for now and appreciate your help!

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.

Was this answer helpful?