How to structure Storyblok spaces using Atomic Design
Storyblok is the first headless CMS that works for developers & marketers alike.
Demo live site: https://dawntraoz.github.io/atomic-design-storyblok
Demo open source repository: https://github.com/Dawntraoz/atomic-design-storyblok
As a developer, it gets easier to structure code, and feel more comfortable making changes, as you gain experience with different projects.
When I start a coding project, I know that I am not the only one who will use it so my structure must fit all users.
This is where Atomic design comes into the picture. 💘
What is Storyblok?
Storyblok is a Headless CMS (Content Management System), the place where you will edit, add and delete your content. Instead of having a markdown file in your FrontEnd project, you will have a website where you will go and start writing content.
A Headless CMS is a back-end only content management system built as a content repository that makes content accessible via an API for display on any device. The term headless comes from the concept of chopping the “head” off the “body”, the “front“ off the “back“ .
What makes Storyblok stand apart from other Headless CMS is that it has a real-time Visual Editor. It provides developers with all the flexibility they need to build reliable and fast websites, while giving content creators with no coding skills the ability to edit content independently of the developer.
What is Atomic Design?
Atomic design is a methodology for creating design systems based on concepts in chemistry. There are five distinct levels to be aware of. They are as follows:
This is the smallest unit that composes our application, it is not useful by itself but it allows you to have more control over the application elements.
An atom could be an input or a label, but to have a semantically correct field you would need the combination of both. They are not useful until you combine them at the next level.
As in nature, molecules are groups of atoms linked together. In an application, molecules are composed by one or more atoms, building a reusable component.
As mentioned above, you can group the input and the label to create the field.
Are groups of molecules joined together to form a distinct section of an interface.
If you take combinations of field-type molecules and put them together with a button-type atom you create a form, which can be thought of as an organism.
Now, chemistry-based theory is set aside to return to the common web language.
Templates can be thought of as the skeleton of your page, made up of groups of organisms and/or molecules to form the common structure of a page.
You can have, for example, a template for the articles on your website (blog-post) and another for the sign forms (register).
Pages are instances of the templates filled of real data.
The structure of the template and the page is the same, but the page will have the final content that you will show to the end user.
This is a brief overview of how this methodology works, but if you want to know more details I recommend you read the book Atomic Design by Brad Frost
‘Atomic design is like mental model to help us think of our user interfaces as both a cohesive whole and a collection of parts at the same time’ - Brad Frost
Why combine Storyblok with Atomic Design?
In order to answer this question, we need to consider how to structure a FrontEnd project and how content creators can use StoryBlok to do their jobs effectively.
This is where Storyblok really shines!
- Control over the contentYou have more control over the content you and your team are creating, because you work with a methodology that makes you reuse the components you have created.
- Easily scaleIt's easy to scale your applications because you have reusable components in place.
- Align with all team membersIt's easy to align with designers and frontend teams because they already know about design systems and they will understand better how you are structuring your space.
- Single source of truthYou will generate a common language and a single source of truth by using the same methodology between teams, creating a design system.
- Improve reusabilityAs you are using reusable components, you will improve reusability, it will be easy to update your application or change the behavior/look'n'feel and you will have less components to fight with.
Now that we've outlined Storyblok's advantages, let's look at a real-world example! 🚀
Structuring our Storyblok space
Let's see how to create each level, which composes Atomic Design, in our Storyblok space and/or our FrontEnd project.
This level is only part of our code.
In this case, the molecules are the components that fill the atoms through properties. So, the atoms don't need to be in our space, the molecules will do the work for them.
Although this methodology is applicable to any framework/library- for these examples I will use Vue.
Now imagine that we have created a Vue project; the next step is to go to the components folder and add a folder to store our atoms, called atoms.
One of our atoms could be Paragraph.vue, where we will create a
<p> html tag that will receive a property with the content.
But obviously, an atom can have more than one property and have different styles. For example, in this component Heading.vue, we can apply different font styles for each type of tag: h1, h2, h3, ..., having the control of how it will be shown, wherever it is called.
If you want to see more examples of atoms, here is the repository created for this demo https://github.com/Dawntraoz/atomic-design-storyblok/tree/main/components/atoms.
This level will affect your code, creating a component that defines how to call the atoms, and the structure of your space, creating a component that awaits the content of the atoms.
Let's look at it more closely with a case study. We'll try to create a molecule that imitates this look and feel:
These are the steps we need to follow to create a molecule in our space:
1. Define a folder to group our molecules
To do that, go to the Components section, which you can find in the left menu, and create a group called molecules, by filling in this input and pressing the add button:
2. Create a new component
Click the New button, in the top right corner, and give your molecule a name, for example, heading-section, and leave it as Nestable, per default.
3. Define its properties
Once we have the component created, we can define the fields that the content creator will fill in and which we will receive in our code.
For this example we need two text type fields, named title and subtitle, and a textarea field, named intro.
In the Code
To create a molecule in our Vue project, we'll follow a process similar to the one we have done with atoms. First, create a folder called molecules and inside create a component called HeadingSection.vue, which will contain 2 Paragraph atoms and a Heading atom.
This time the component will receive the blok property, which is part of the response returned by the Storyblok API, and will contain the title, subtitle and intro properties already defined.
We only have to pass the content that comes from the API to the properties of each atom, as you can see below:
To see more molecules examples, check out this folder inside the repo: https://github.com/Dawntraoz/atomic-design-storyblok/tree/main/components/molecules
As with molecules, this level affects our code and our space.
For this level, consider the idea of encompassing several molecules together, one of them being the heading-section described above:
1. Define a folder to group our organisms
Being in the Components section, we create a group called organisms, by the form:
2. Create an organism.
Click the New button again and give your organism a name according to the name of the section. Because we are representing a number of services let's call it services and, again, leave it as Nestable.
3. Define its fields.
Once we have the molecules needed for this organism, we can define the fields that will expect a molecule as the content.
For this example, we need two blocks fields called heading, with a heading-section molecule, and services, with one or more service-card molecules.
Blocks fields allow you to add another component created in the Storyblok space as content, instead of adding a text or a link for example. Read more about them in the Storyblok developer guides.
To make it easier to understand let's see what the property heading contains. We can see, in the screenshot below, that the type of this field is blocks and it only allows heading-section components to be inserted. Actually, only 1, as specified by the maximum allowed.
In the Code
When it comes to creating an organism in our Vue project, it is even easier.
First, create a folder called organisms. Inside, create a component called Service.vue, which will contain 2 dynamic components. These dynamic components will be calling our molecules coming from the API response.
As you can see in the snippet below, this time the component will receive the blok property but, also, will fill in the blok property from the molecules.
The blok object will contain an array with only one item in heading, since we have set the maximum allowed to 1. But, in the case of services, we will have an array of 4 elements at most.
Each element of the arrays will contain the type of component (heading.component): heading-section.
To see other organisms in place, check out this other folder: https://github.com/Dawntraoz/atomic-design-storyblok/tree/main/components/organisms.
Again, this level will affect the code and our space.
But this time the component type on our space will no longer be Nestable (the default) but Content-type.
Content Types allow you to create templates for your content. Examples of common Content Types are blog-post, page. Read more about them in the Storyblok developer guides.
We don't need a folder anymore, instead, we can create the template in the main folder All.
1. Create the template.
Go to the New button and give your template a name, according to the content it will receive. Since we are representing a common page in our application let's call it page-template. Then check Act as content type and exclude Nestable.
2. Define the body field.
Now that we have the molecules, which receive the content that will reach the atoms, and the organisms, which can already call the molecules they need, we need to create the template that calls those organisms.
To do this, we created a block type body field that will only allow us to call the components that are inside the organisms folder. In this way, we achieve a maximum of three levels of nesting depth in our panel of contents (page > organism > molecule).
In the Code
In this case, the template component could be created inside the components folder, **without creating a new folder.
Create a component called PageTemplate.vue, which will contain a dynamic component, that represents the organisms that the content creators have added to our content panel.
The blok object contains an array with the organisms inside of the body.
Each element of the arrays will contain the type of component (block.component): services (the organism).
The last level will only be a part of our code (view: eg. index).
This is the view that will call the Storyblok API, with a fetch or axios call, and receives the data.
This data is then passed to the corresponding template, in this example page-template. The template will in turn pass the data to the organisms, then to the molecules, and, finally, end up with the atoms.
Passing the data from parent to child.
Using Atomic design, we have created an ecosystem that enables content creators to re-use the organisms we defined and fill their related molecules with content.
Every developer uses methodologies that suit their project needs. In this case, I have explained a methodology that will help you to build a Design System. If this makes sense for you too, give it a shot, and let me know how it went!
|Recording of the Talk||https://youtu.be/DThhHwEec8Q|
|Atomic Design Methodology||https://bradfrost.com/blog/post/atomic-web-design/|
|Atomic Design Book||https://atomicdesign.bradfrost.com/|
|Blok (Nested Component)||https://www.storyblok.com/docs/guide/essentials/content-structures#blok-nestable-component|