Almost EVERYONE who tried headless systems said they saw benefits. Download the state of CMS now!

Storyblok now on AWS Marketplace: Read more

O’Reilly Report: Decoupled Applications and Composable Web Architectures - Download Now

Empower your teams & get a 582% ROI: See Storyblok's CMS in action

Skip to main content

How to use Nuxt components inside Storyblok Rich-Text editor

Try Storyblok

Storyblok is the first headless CMS that works for developers & marketers alike.

  • Home
  • Tutorials
  • How to use Nuxt components inside Storyblok Rich-Text editor

I will talk about a feature of Storyblok that is not highlighted enough, yet is extremely powerful. The rich-text field, and more specifically, the possibility of inserting components.

To provide some context, the rich-text at Storyblok is based on prosemirror.

Section titled Why use Richtext with Storyblok? Why use Richtext with Storyblok?

I am going to provide an example of how to use it and small tips that will bring you the added value for its use.

Section titled Storyblok configuration Storyblok configuration

You have a Nuxt project with storyblok-nuxt installed. From there you can start using the rich-text feature of Storyblok.

Section titled Define components Define components

For the Storyblok part we will create a home page like in the image below.

The body part here is our focus-it will be our rich-text. The small configuration that I like to use when I write my articles is to disable the preview.

Before going into detail, we will first create the two components to use in our rich-text.

Section titled Our blokDoubleImage Component Our blokDoubleImage Component

The blokDoubleImage represents a block with 2 images taking 50% of the space.

Section titled Our blokSupport Component Our blokSupport Component

The blokSupport represents a banner in the flow of the page, composed of an URL, an image of the person and a description text .

For each component I suggest you use the preview functionality.

Screenshot or icon:

This option lets you define a screenshot that gets shown when the user inserts a new component in the blocks field. This helps the user to better identify the component type.

This gives you a mini-preview of your components which helps your users see what they are going to use.

Example:

We will now configure and insert our two components in the rich-text.

Et voila ! Now we can move on to Nuxt!

Section titled Nuxt Configuration Nuxt Configuration

So now we want to do the following:

  • Prepare our components
  • Call the content of our home page
  • Render our rich text with the components.

Section titled Prepare our components Prepare our components

You must make sure that the name of the components will be the same as that on Storyblok.

Example: BlokInfo should be BlockInfo too or blok-info.

BlokDoubleImage.vue

        
      <template>
  <div class="flex -mx-2 my-4">
    <div class="px-2 w-1/2">
      <div
        class="bg-image"
        :style="{ backgroundImage: `url('${body.one.filename}')` }"
      ></div>
    </div>
    <div class="px-2 w-1/2">
      <div
        class="bg-image"
        :style="{ backgroundImage: `url('${body.two.filename}')` }"
      ></div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    body: {
      type: Object,
      required: true,
    },
  },
}
</script>

<style lang="postcss">
...
</style>
    

BlokSupport.vue

        
      <template>
  <div class="support w-full lg:w-1/2">
    <div class="rounded-lg shadow-xl p-4 flex">
      <div class="flex items-center w-1/3">
        <img
          :src="body.avatar.filename"
          :alt="body.avatar.alt"
          class="rounded-full object-cover"
        />
      </div>
      <div class="p-2 w-2/3">
        <p class="mb-4">{{ body.description }}</p>
        <a
          target="_blank"
          :href="body.url"
          class="bg-yellow-400 text-black px-4 py-2 rounded-lg flex items-center w-40"
        >
          <Coffee class="w-6 h-6 mr-2" />
          <span>Buy coffee</span>
        </a>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    body: {
      type: Object,
      required: true,
    },
  },
}
</script>

<style lang="postcss">
...
</style>
    

Section titled Call the content of our home page Call the content of our home page

In your index.vue use the following code.

index.vue

        
      <template>
  <div class="m-auto w-full md:w-2/3 px-4">
    <h1 class="text-6xl font-bold mb-4">{{ title }}</h1>
    <p class="text-lg mb-8">{{ description }}</p>
    <div class="mb-8">
      <SbRichText :text="body" />
    </div>
  </div>
</template>

<script>
export default {
  async asyncData({ app }) {
    try {
      const { data } = await app.$storyapi.get(`cdn/stories/home`, {
        version: process.env.STORYBLOK_VERSION || 'draft',
      })
      return {
        ...data.story.content,
      }
    } catch (e) {
      console.error(e)
    }
  },
}
</script>
    

Section titled Render our rich text with the components. Render our rich text with the components.

First create the rich text component.

SbRichText.vue

        
      <template>
  <div>
    <RichTextRenderer :document="text" />
  </div>
</template>

<script>
export default {
  props: {
    text: {
      type: [String, Object],
      default: '',
    },
  },
  computed: {
    richtext() {
      return typeof this.text === 'string'
        ? this.text
        : this.$storyapi.richTextResolver.render(this.text)
    },
  },
}
</script>

<style lang="postcss" scoped>
... your css for your rich text
</style>
    

By default, Storyblok's rich-text component is not able to render inline components. To do this you need a compiler. In our case, I suggest you use storyblok-rich-text-renderer.

You will have to install it.

        
      yarn add --dev @marvr/storyblok-rich-text-vue-renderer

yarn add --dev @vue/composition-api // It needs vue composition api to make it work.
    

Create two plugins:

plugins/composition-api.js

        
      import Vue from 'vue'
import VueCompositionApi from '@vue/composition-api'

Vue.use(VueCompositionApi)
    

plugins/rich-text-renderer.js

        
      import Vue from 'vue'
import VueRichTextRenderer from '@marvr/storyblok-rich-text-vue-renderer'
import blokDoubleImage from '@/components/bloks/blok-double-image'
import blokSupport from '@/components/bloks/blok-support'

Vue.use(VueRichTextRenderer, {
  resolvers: {
    components: {
      blokDoubleImage,
      blokSupport,
    },
  },
})
    

Don't forget to update the config of the Nuxt.

./nuxt.config.js

        
      export default {
	...
	plugins: ['~/plugins/composition-api.js', '~/plugins/rich-text-renderer.js'],
}
    
IMPORTANT:

You must follow the order exactly or it will not work.

Section titled Conclusion Conclusion

Voila! Now your components should be rendered. You can create a full component library and give freedom to your content creator. The only limit is your imagination!

Author

Florent Giraud

Florent Giraud

I am a software developer. I am a NuxtJS Ambassador. I like to watch animes, eating good food and challenging myself about everything.