Let's understand what Storybook decorators are and how to create them.
Let's assume that we want to wrap our Page stories so that in Storybook, they are inside a bordered container which is centered and has a max-width of 400px.
We can do that by changing the template function to look like this:
And you should see the results in the stories:
However, it's not great to keep that in the template as you might want to reuse this code in other places as well. Storybook has a concept called Decorators, which allows us to better achieve this.
Decorators are basically wrappers that receive a Story component and enhance it in a certain way. They are used to either provide visual enhancements or functionality (e.g. theming, state management, etc.).
We can extract the logic from the template and create a decorator from it:
The decorator is an annotation that can be applied to every story if declared in the meta:
Things should work the same!
That's great! But what if we only want the decorator applied in one story of our component?
Instead of passing the decorator to the meta like we did before, you pass it to the
decorators property of a story:
That's it – now the decorator is only applied to the LoggedOut story. But what if we want the decorator to be applied in every single story of our project?
Let's first of all extract the code for our decorator. It's a good practice to gather the decorators that you want to share in your stories in a
.storybook/decorators.tsx file. Let's create one and add the following code:
To declare global decorators in Storybook, all you have to do is import the decorators you want to apply globally and export them in a named export called
decorators under the
Now, all stories of all components will have a maxWidth container.
If we want to make the code more scalable, we can refactor the
.storybook/decorators.tsx file to already export an array of all decorators that should be globally applied to storybook, like so:
and then update the reference in the
And there you go! We should be all set! This is a great way to organize code because
preview.js might contain a lot of other configuration and might become a bit too long. Keeping the decorators in its own file will make it simple for others to identify them, as well as understand which ones are applied globally by looking at the
Because this exercise was mostly experimentational, let's not keep the decorator globally:
In Storybook, the order of the decorators matter. This is because, before rendering a story, Storybook will run every decorator applicable to that story, in the following order:
Global decorators, in the order they are defined.
Component decorators, in the order they are defined.
Story decorators, in the order they are defined.
This means that a Story component will be wrapped by all of the decorators, from innermost to outermost. Given that, it's important to always pay attention to the order that you define your decorators in. The following pseudocode might help you visualize this:
In the next lesson, we will learn about Addons and explore the essential addons that come by default with Storybook.