Stories, Chapters and Paragraphs: Structuring Content with Storyblok and Vue.js
Storyblok is the first headless CMS that works for developers & marketers alike.
Structuring the content for complex sites like homepages and landing pages, can be a very challenging task. For the longest time most content management systems weren’t really well suited for dealing with complex content structures. With the rise of headless content management systems things have changed pretty fast. The decoupling of the data layer and the rendering layer makes it easier to forge complex data structures on the one side and render the data on the frontend with full control over the markup.
Thanks to the concept of Components and Blocks, Storyblok is even more powerful in that regard than most other headless content management systems. In this article, we'll take a look at how we can structure the content for complex landing pages with Storyblok in a way that we can reuse a lot of the building blocks. This makes it possible to build multiple landing pages, with different layouts but the same basic building blocks, in no time. Additionally, we will build a simple Vue.js app that will make it very easy for us to render our complex data.
The building blocks: Stories, Chapters and Paragraphs
Inspired by the “Story” naming pattern I've come up with two extra ingredients for crafting stories: Chapters and Paragraphs.
Every building block, no matter if Story, Chapter or Paragraph, is a Storyblok Component.
Stories
Like a real story, Stories usually have one or multiple Chapters. Stories in Storyblok are content types. When following the methodology of this article, usually the only field of a Story is a field named chapters
which is a field of type Blocks referencing one or multiple Chapter components, but you might also add additional fields for meta informations directly to the Story component.
Chapters
Chapters are the core components of any Story. In our system all the main pieces of content like text or images, must live inside of a Chapter or a Paragraph. So each chapter can have one or multiple fields. Furthermore, chapters can (but don't have to) consist of multiple paragraphs.
The main reason why we differentiate between Chapters and Paragraphs is that Chapters control the layout of the piece of content. So Chapters must have a layout configuration field.
The layout configuration component
In this example, our Chapter layout configuration is responsible for two things: the width of the Chapter and the spacing around it. But you could add more configuration options like the possibility to change the background color for example.
Our chapter configuration is a separate component. We create it by adding a new component with the name of config
.
Next we add two new fields to the schema of our newly created configuration component: a spacing_top
field, which makes it possible to configure the the spacing between two chapters and a field named container
which we'll use to control the width of Chapters.
As you can see in the screenshots above, the two fields of our configuration component, are configured exactly the same. Both are Single-Options fields with three options: Small
, Medium
and Large
. In the case of the spacing_top
field those options represent the size of the spacing which is added to the top of the Chapter. The value of the container
field determines the width of the Chapter.
Paragraphs
Paragraphs are very similar to Chapters with the main difference being that Paragraphs do not have a layout configuration field. Typical use cases for Paragraphs are teaser blocks or other highly reusable building blocks.
Building a landing page story
After defining all the available categories of building blocks which we have at our disposal, let's actually build a landing page story.
Our landing page Story component is rather simple: it only contains one field for referencing the Chapters which make the Story.
Adding Chapters
To demonstrate the power of this methodology we create three Chapters. An Intro Chapter for rendering a headline and some large intro text. A Media Object Chapter for rendering combinations of images and text. And last but not least a Multi Column Teaser Chapter which we'll use to display a list of Card Paragraphs.
In the screenshot above, you can see all three Chapters. The headline + text combination is the Intro Chapter. The Intro Chapter is followed by the Media Object Chapter after which you can see the Multi Column Teaser Chapter.
The Intro Chapter
We want our landing pages to start off with a headline and a short introduction about the topic of our landing page. Let's add a new chapter_intro
component which makes this possible.
As you can see above, our Intro Chapter component consists of three fields: headline
, text
and config
. The first two fields are simple text fields but let's take a closer look at the settings of the config
field.
The config
field is of the type Blocks. But we restrict the set of components to only allow the config
component to be added. Also only a single config component is allowed and the user is required to add one config component.
The Media Object Chapter
Next on the line is the Media Object Chapter. We want this chapter to contain an image field and a field containing some text. Both fields use the default options. Again the config
field uses the same options as we've already seen previously in the Intro Chapter.
Multi Column Teaser Chapter
Last but not least we create the Multi Column Teaser Chapter. We want this Chapter component to render multiple Card Paragraph components. So let's create the Card Paragraph component first.
The Card Paragraph component consists of three simple fields: an image, headline and a text field. All of those fields use the default options.
Now we're ready to create our Multi Column Teaser Chapter component.
The Multi Column Teaser component consists of only two fields: the teasers
which is of type Blocks and a config
field which uses the same options as we've already seen in the Intro Chapter. In the screenshot below you can see the teasers
fields configuration options. We restrict the set of components to only paragraph_card
and we allow a maximum of 3
components to be added.
Writing a Story
Now we have all the necessary building blocks at our disposal to create a new Landing Page Story. First we create a new content of type Landing Page.
Next we can add new Chapters to our Story. As you can see in the following screenshot, the Chapters we've created earlier are now available as our contents for creating Stories.
Rendering Stories in Vue.js
After writing our story, we're ready to render it in our frontend of choice. In the following example I'll use Vue.js but you can take the basic idea and build something similar with any frontend or backend framework you like.
In the code snippet above you can see the ChapterLoader
component which is responsible for loading the given Chapter components. Here you can see that we're dynamically importing the matching Chapter components for which we defined the data structures in Storyblok earlier.
The ChapterLayout
component you can see above, takes the data from the config
data component and applies u-spacing-top-*
and o-container--*
classes to the Chapter layout wrapper. The u-spacing-top-*
utility class is responsible for applying margin-top
to the Chapter. The o-container--*
class limits the width of the Chapter.
Wrapping it up
If you're thinking about structuring the content of your Storyblok project in a similar way as we did above, keep in mind that this approach is designed for more complicated websites. If, what you build is a very simple site and you don't need your content editors to be able to build complex layouts themselves, you might be better off keeping it as simple as possible.
On the other hand, if you want your content editors to have full control over the layout of new landing pages they build completely by their own, this approach might be a powerful solution.