Building a List Field Type Plugin
Storyblok is the first headless CMS that works for developers & marketers alike.
In this article we'll take a look at how to build a field type plugin for Storyblok to handle content for lists. E.g. a list of benefits of your product or service.
In the screenshot above, you can see an example for a typical use case for a list. In the following chapters we'll find out how we can build a plugin which makes it very easy for content editors to add the content for such lists.
Setup
Storyblok provides us with a very potent plugin system based on Vue.js components. This makes it possible to build field type plugins for every imaginable use case. Although, for very basic plugins, you can use the simple in-browser editor provided by Storyblok itself, usually we need to set up a simple development environment first, before we can get started building our custom plugin.
There already is great documentation about how to set up a local development environment for building Storyblok plugins. Please follow the steps described in the article and come back when you‘re ready.
After setting up a fresh local development environment and starting the development server with npm run dev
we're ready to start developing our own plugin.
Above you can see the example plugin provided by the Storyblok plugin boilerplate. In the next step we'll replace this with our own implementation of a list field type plugin.
Creating the list plugin
We want our plugin to be rather simple: it should allow our content editors to enter a couple of list items. In order to make that happen it should be possible to enter some text in an input field and add additional input fields for more list items. We also want to provide a configuration option to make it possible to limit the amount of list items a content editor should be able to add.
Planning the data structure
The final data structure, which we want to get as a response from the Storyblok API, should look something like this.
In order to keep it simple, our plugin returns an array of plain strings. If you're planning to add additional functionality like choosing the bullet characters or making it possible to nest list items, you should consider to use a data structure like the following in order to be prepared for future changes.
By using objects to store the data for each list item, you'll be able to add additional properties in the future. But for this article we keep it as simple as possible.
Coding the plugin
Now that everything is set up and ready to go, let's get our hands dirty and write some code. In the following code snippet, you can see the basic code of our Plugin.vue
file in the src
directory of our project.
Above you can see the bare minimum implementation for our list plugin. In the <template>
part of the component you can see that we render a list of <input>
items. We connect each <input>
item with the data in our model via v-model="model.items[index]"
.
In the <script>
part we can see the boilerplate code to make our component work as a Storyblok field type plugin. In the initWith()
method we specify the initial value of our plugin with items: ['']
, which means, at the beginning, we have one empty list item. Next we define the name of the plugin via plugin: 'list'
.
The <style>
section only contains a reset of the default padding
on lists and we add some spacing between list items. All other styling is done via UIkit classes.
Adding new items
Next up we want to add the functionality to add additional list items. Let's update our code to enable this.
First we add a new <a>
element to the template section of our plugin. We also bind a click handler on it via @click="addItem"
. This means that the method addItem()
is called every time the button is clicked.
Above you can see the addItem()
method we've specified as a click handler on our newly added button. Every time it is called, a new empty string is added to the list of items. Adding a new list item automatically triggers a new <input>
element to be rendered.
Removing items
So far so good. Now we're able to add new items to our list, but what about removing existing ones?
The first change you can see is that we've added the uk-flex
and uk-flex-middle
UIkit helper classes in order to display the elements inside of our list item side by side and vertically centered. Next we've added a new <a>
tag containing a minus icon which signals to the user that this is for removing this item. We've also added a @click
event handler to call the removeItem()
method with the index of the current item.
The removeItem()
method receives an index
and uses it to filter the list of items to remove the item with the given index.
Item limit
Last but not least we want to make it possible to limit the number of list items our users are allowed to add to a certain piece of content. Fortunately it's possible to pass options to field type plugins. In the screenshot below, you can see how to pass options in development mode and that the Add item
button is not rendered anymore if the limit is reached.
Let's take a look at the changes we have to apply to the code of our plugin to make this work.
In the <template>
section we add a v-if="!limitReached"
directive onto the <a>
tag of our Add item
button. That way we make sure that the button is only rendered if the specified limit is not reached yet.
In order to provide the information if the limit is already reached or not, we specify a new limitReached
computed property inside the <script>
section of our component. We can access the limit
passed to the plugin via this.options
. By comparing this value to the length
of the array of items we can find out if the limit is already reached or not.
Using the list plugin
After we're done coding, we can build our plugin by running npm run build
and copy and paste the generated code from dist/export.js
into the editor text field of the Storyblok app and click the publish button.
Now that we've successfully added our plugin to our Storyblok space, we're able to use it in our content types. Let's edit the schema of the content type for which we want to provide a list of data.
After setting up the new field and adding some list items, we're ready to consume the data in our application.
Final notes
This is a rather simple implementation of this kind of field type plugin. Depending on your use case you can extend its functionality and tailor it exactly to your needs. For example you could add the possibility to choose which icon is used as bullet character. Or you could add the possibility to build nested lists or you might add a drag and drop feature for reordering list items.