Add a headless CMS to VueJs in 5 minutes

In this short article, we will show you how you can use the API-based CMS Storyblok for components in combination with the progressive JavaScript Framework “Vue.js”. At the end of this article, you will have a Vue.js Application which renders components filled with data from Storyblok.

Storyblok added in vuejs

Let me start with a short explanation of Storyblok first: Storyblok is a headless CMS in which you can create components nested in Stories (If you want to create a website you can go with - a story equals to a page). The key concepts behind Storyblok are highly inspired by the BEM methodology. The author of a story can create a nested tree of components and input content in an easy and fast responding interface (also made with vuejs btw).

During this article, for example, we will use following JSON which comes from the Storyblok API to render our first story:

/v1/cdn/stories/home
$ curl https://api.storyblok.com/v1/cdn/stories/home?token=akYA0RB4BzCPUoRfjIvUdQtt
/v1/cdn/stories/home
{
  "story": {
    "name": "home",
    "content": {
      "component": "root",
      "body": [
        {
          "component": "teaser",
          "headline": "Easy - isn't it?"
        }
      ]
    },
    "slug": "home",
    "full_slug": "home"
  }
}

Vuejs

I’m sure that most of you are already familiar with Vue.js and it’s basics - if not - Here you can find their introduction.

Let’s start with the installation of their command line interface to get the thing running:

command line
npm install -g vue-cli

(Prerequisites: Node.js (>=4.x, 6.x preferred), npm version 3+ and Git.)

Start a new vuejs project

You can add Storyblok to existing projects as well - for simplicity we will show how to add Storyblok to a completely fresh project - so a beginner to the world of Vue.js can use Storyblok as their CMS as well. Execute the following commands so you get a new project ready to start with:

command line
vue init webpack vue-storyblok

cd vue-storyblok && npm install && npm run dev
start a new vuejs project.

Including the Storyblok script

You will need to include the Storyblok script in order to use the side by side editor. The script comes also with an API for getting content and subscribing to events like “update”, “published”, …

/index.html
<script type="text/javascript" src="//app.storyblok.com/f/storyblok-latest.js"></script>

Install our Vue.js Plugin

The Storyblok Vue.js plugin allows you to make any element editable with Storyblok by just adding v-editable="content" to an HTML element.

command line
npm install storyblok-vue --save-dev
Install the storyblok vuejs plugin.

In your /src/main.js, we import the plugin so vuejs will be able to use it.

/src/main.js
import StoryblokVue from 'storyblok-vue'

Vue.use(StoryblokVue)

Load our first story

Let’s open the /src/components/Hello.vue and add an empty story to data.

/src/components/Hello.vue
data () {
  return {
    msg: 'Welcome to Your Vue.js App',
    story: {
      content: {
        body: []
      }
    }
  }
}

As you can see this is the basic form according to the JSON at the beginning - the content can be any component you want - defined by yourself. For this example, we prepared a property called body which is an array of sub-components (e.g. teaser).

Next, we will have to initialize the Storyblok client so you will have access to your space & the connected stories - you can switch the accessToken to one of yours afterwards.

/src/components/Hello.vue
created () {
    window.storyblok.init({
      accessToken: 'akYA0RB4BzCPUoRfjIvUdQtt'
    })
    window.storyblok.on('change', () => {
      this.getStory('draft')
    })
    window.storyblok.pingEditor(() => {
      if (window.storyblok.isInEditor()) {
        this.getStory('draft')
      } else {
        this.getStory('published')
      }
    })
  },

You may notice the this.getStory method in our created block. This method doesn’t exist yet. So let’s add the method to the vue.js methods. You can see that we’re using the clients .get function to load a story according to the slug:

/src/components/Hello.vue
methods: {
    getStory (version) {
      window.storyblok.get({
        slug: 'home', 
        version: version
      }, (data) => {
        this.story = {
          content: {
            body: []
          }
        }
        this.$nextTick(() => {
          this.story = data.story
        })
      })
    }
  }

Good Job!

You’ve loaded your first story - now we only have to display the data we already received. Let’s change the template of the Hello.vue to something more generic than a static logo and links:

/src/components/Hello.vue
<template>
  <div>
    <component :blok="story.content" :is="story.content.component"></component>
  </div>
</template>

This will include a component according to the components added in the Story we already loaded.

Now let's create our first nested component

In the JSON above we can see that the object of the root component (don’t mind the name - in Storyblok, you can name components as you want.) only has one array as property - body:

/v1/cdn/stories/home
...
"body": [
  {
    "headline": "Easy - isn't it?",
    "component": "teaser"
  }
]
...

All we need to do now is to iterate through all the components which are nested in the array.

We need to create a Root.vue file in our project which would look like the following to achieve that:

/src/components/Root.vue
<template>
  <div v-editable="blok">
  <template v-for="item in blok.body">
    <component  :blok="item" :is="item.component"></component>
  </template>
  </div>
</template>

<script>
export default {
  props: ['blok']
}
</script>

You can see that in each iteration the property :blok="item" will be passed to the child component.

Don’t forget to register the new component in your /src/main.js so Vue knows about it.

/src/main.js
import Root from '@/components/Root'

Vue.component('root', Root)

The next component we need to add to finally display something is the teaser component.

/src/components/Teaser.vue
<template>
  <div class="teaser">
    <!--
    The _editable attribute makes the next
    DOM-element clickable so the sidebar can
    show the right component.
    -->
    <div v-editable="blok" class="teaser__inner">
      <h1>
        <!--
        You can access every attribute you
        define in the schema in the blok variable
        -->
        {{blok.headline}}
        </h1>
        <h2>
          You can create new components like this - to create your own set of components.
      </h2>
    </div>
  </div>
</template>

<script>
export default {
  props: ['blok']
}
</script>

and register it again in your /src/main.js:

import Teaser from '@/components/Teaser'

Vue.component('teaser', Teaser)

Congrats!

You’ve added Storyblok to VueJs.

Storyblok with vuejs - easy - isnt it?

Configuring Storyblok

Now that you have successfully integrated Storyblok in your project let’s create a “Story” in your own Storyblok space.

Using the CLI:

  1. npm install -g storyblok
  2. storyblok quickstart

Using the Webinterface:

  1. Go to https://app.storyblok.com/#!/signup and do the signup
  2. Create a new Space.

Both ways will start with the quickstart which will guide you through your first time creating a component in Storyblok.

Follow the quickstart

Exchange the private token

Copy your private token to receive the draft version of your content. The private token is a read only token. If you don’t want that the draft version of your content will be visible for the public you need to protect it via a server side client. Insert your token in “Hello.vue”.

created () {
  window.storyblok.init({
    accessToken: 'INSERT_YOUR_TOKEN'
  })
  ...
Create private access token

Add your environment

After adding your own token from your Space to your project - we will have to also tell Storyblok where to find our dev environment. For this we will navigate to the Settings of a Space and add the URL http://localhost:8080/ as a new environment.

add a dev environment

Well done!

Try out to insert a text and click “Save”. Your component should now be updated with the new content. Next step is to repeat the steps above to configure more components. You can also create grid and column components which can nest other components with the schema type “components”. A root component is such a component which has other components nested.

Final Part

Components in this Tutorial

Component NameComponent Use
rootholder for all nested components - only has a property of the typ "components".
teasercontains the property "headline" so the components headline can be edited in the SideBySide Editor.

Video and the code of this tutorial

The whole code of this tutorial you can also find on github at https://github.com/storyblok/vuejs-boilerplate. Checkout also the video to see all steps in action:

Next: Learn about components

How thinking in components can increase your productivity? Components are units of code that are nestable, reusable and decoupled. They help you to don’t repeat yourself writing the same functionality or HTML tags multiple times. They ease the process of thinking because…


More to read...

About the author

Dominik Angerer

A web performance specialist and perfectionist. After working for big agencies as a full stack developer he founded Storyblok. He is also an active contributor to the open source community and one of the organizers of Stahlstadt.js.