August 27, 2021 Link to lesson

Rich Text Storyblok Field with TailwindCSS

Using Rich Text Fields in your content model will provide your authors more flexibility to include various kinds of formats including heading, code blocks, bold and italic and more. Once that content is in Storyblok, we need to render it and display it properly on a delivery. In this lesson you will learn how to render RTF fields in your application using TailwindCSS.

Rich Text field capabilities

  1. CUSTOM TOOLBAR

    This option lets you define the toolbar items that will be shown in the Rich Text field.

    Customize toolbar items
    Customize toolbar items
  2. CUSTOM CLASSES

    This option lets you define custom CSS classes for the user using key/value pairs.

    Add custom classes by label/value
    Add custom classes by label/value
  3. CUSTOM COMPONENTS

    The option Allows only specific components to be inserted lets you define the components that can be inserted by the "Add block" toolbar button.

    Option 'Allow only specific components to be inserted' checked
    Option 'Allow only specific components to be inserted' checked

Rendering the Rich Text field

To render the content of the Rich Text field, Storyblok provide us with a render method in the SDKs.

You can find the way to render the Rich Text field in any programming language in the official documentation.

JavaScript SDK

The code below shows you how to render a Rich Text field with the Storyblok JS client.

  
    
const StoryblokClient = require('storyblok-js-client')
 
let Storyblok = new StoryblokClient({
  accessToken: 'API_TOKEN'
})

// Method to render the rich text field
// -- Input: data.richtext_field (JSON)
// -- Output: HTML string
Storyblok.richTextResolver.render(data.richtext_field)

  

To render custom components, in case they're allowed to be inserted, a component resolver function will be needed:

  
    
Storyblok.setComponentResolver((component, blok) => {
  switch(component) {
    case 'my_button':
      return `<button>${blok.button_text}</button>`
      break;
    case 'contact_form':
      return `<a href="mailto:${blok.mail}">Mail me at: ${blok.mail}</a>`
      break;
  }
})

  

Solution for Nuxt using Vue Composition API

First, we need to have installed in our Nuxt project the module storyblok-nuxt that will provide us the configuration of the JavaScript SDK.

 yarn add -D @storyblok/nuxt axios 

And then in a Nuxt component, we will be able to use the richTextResolver.render from the Storyblok API instance.

  
    
// RichTextRender.vue
<template>
  <div>
    <div v-html="richtext"></div>
  </div>
</template>
 
<script>
export default {
  props: ['richtext'],
  computed: {
    richtext() {
      return this.richtext ? this.$storyapi.richTextResolver.render(this.richtext) : ''
    }
  }
}
</script>

  

But as we have seen before, to render custom components we need a component resolver function.

For that, we will use the Storyblok Rich-Text Renderer develop by the Storyblok community 🎉.

Full details can be found in the guide How to use Nuxt components inside Storyblok Rich-Text editor.

 yarn add -D @marvr/storyblok-rich-text-vue-renderer @vue/composition-api 

And configure these two packages in the plugins folder:

  • composition-api.js:

      
        
    import Vue from 'vue'
    import VueCompositionApi from '@vue/composition-api'
    
    Vue.use(VueCompositionApi)
    
      
    

  • rich-text-renderer.js:

      
        
    import Vue from 'vue'
    import VueRichTextRenderer from '@marvr/storyblok-rich-text-vue-renderer'
    import CustomComponent from '@/components/custom-component'
    
    Vue.use(VueRichTextRenderer, {
      resolvers: {
        components: {
          'custom-component': CustomComponent,
        },
      },
    })
    
      
    

And then, add them to nuxt.config.js:

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

  

Finally, the component RichTextRender.vue we've seen before, which will render the custom components too, will be:

  
    
// RichTextRender.vue
<template>
  <div>
    <rich-text-renderer :document="richtext" />
  </div>
</template>
 
<script>
export default {
  props: ['richtext']
}
</script>

  

Example using Tailwind Typography

First, we need to install the tailwind plugin @tailwindcss/typography.

 yarn add -D @tailwindcss/typography 

And then, add the plugin to tailwind.config.js file:

  
    
module.exports = {
  plugins: [
    require('@tailwindcss/typography'),
  ],
}

  

What is Tailwind Typography?

A plugin that provides a set of prose classes to add typographic defaults to any vanilla HTML you don't control.

In this case, the HTML rendered using the JSON returned by the Rich Text field from Storyblok.

What style options do we have?

  • Size modifiers: .prose-sm, .prose, .prose-lg, .prose-xl, .prose-2xl.

    To use different sizes you'll always need the .prose class, example: prose prose-lg.

    You can use it combined with variants too, prose lg:prose-lg.

  • Color modifiers: prose-red, prose-yellow, prose-green, prose-blue, prose-indigo, prose-purple, prose-pink.

    By default is set to gray.

  • Customization: It's possible to customize the styles provided by this plugin, adding a typography key in the theme section of tailwind.config.js.

    Docs on how to customize Tailwind typography.

      
        
    // tailwind.config.js
    module.exports = {
      theme: {
        extend: {
          typography: (theme) => ({
            DEFAULT: {
              css: [
                {
                  color: theme('colors.emerald.700'),
                  a: {
                    color: theme('colors.emerald.900'),
                    textDecoration: 'underline',
                    fontWeight: '500',
                  },
                  hr: {
                    borderColor: theme('colors.emerald.200'),
                    borderTopWidth: 1,
                  },
                  blockquote: {
                    fontWeight: '500',
                    color: theme('colors.emerald.900'),
                    borderLeftWidth: '0.25rem',
                    borderLeftColor: theme('colors.emerald.200'),
                    quotes: '"\\201C""\\201D""\\2018""\\2019"',
                  },
                  h1: {
                    color: theme('colors.emerald.900'),
                    fontWeight: '800',
                  },
                }
              ]
            }
          }),
        }
      }
    }
    
      
    

Styled by prose lg:prose-lg prose-red.

This is a Heading

This is a paragraph with an underlined word, a bold text and a link.

This is a blockquote

  1. This is an ordered list.

  • This is an unordered list.

  
    This is a code block.