How to use Storybook Decorators to Style Components

Let's understand what Storybook decorators are and how to create them.

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the Storybook for React Apps course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to Storybook for React Apps, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course Storybook for React Apps
  • [00:00 - 01:09] Sometimes you might want to add extra markup or functionality to what's rendered in your stories. In example, we have this page stories, which we have a template that basically renders a page component. Let's say we want to wrap the page story into a border container that has a max width of let's say 400 pixels. We can do that by changing our master template, which will look something like this. So we add our wrapper, and then we save this. And then every single story that uses the template will be wrapped in this border container. But it's not great to have this implementation inside of our template. So let's undo the changes we made, and let's apply a concept called decorators, which storybook provides as a way to have an annotation to your story that will essentially wrap a story with some extra markup. So we can create over here, let's say, we normally call it width, and then whatever the decorator does, let's say max width. And the decor ator receives the story event or story function as a parameter. And then it can return the template. So let's just do return right here. And then we add story event as the element, and then we just close our div.

    [01:10 - 01:24] So once we do this, we have to apply this decorators somewhere. And in this case, let's say we want to apply for every single story, we can essentially add to the meta, because it's a component annotation. And the decorators property is an array. So you have to pass like that.

    [01:25 - 01:47] Now I see that the style is being applied the same for every story over here. However, you might want to have the decorator applied only to a particular story. So let's comment this out. And only to the logged out story, let's add decorator to that story level. So you can essentially access your logged out story dot decorators, which is also an array, where you set the width max width.

    [01:48 - 03:52] You see now that the logged in story is correct. And the logged out story has that style applied. But what if you actually don't want this to be in your component level, or even your story level, and you actually want to apply this decorator to every single story of your storybook. That's totally possible. So let's first of all remove the implementation here, and extract this out. How can we do that? Well, first of all, the preview.js file is where we can set some configurations for the rendering of storybook. And that will be applied at a global level. So a good practice is to actually have a decorators file over here, where we can define all of the decorators, which will be used in storybook. And we can export them. And if you want to have better type safety over here, you can import a type from at storybook slash react, called the decorator, FN. And the decorator FN is set over here. Once we set this decor ator, we will look at the preview.js file. And we will be importing it from dot slash decorators. And it's called with max with. And the same way this is exporting a const called parameters, we can actually export a const called decorators. The decorators, once again, is an array. So we set it like this. And then we just put our decorator right here. And as a result, you see that the decor ator was applied to this story to this story, but actually to the header, as well as to the button. So given this setup, what you can actually do is create a const over here in your decorators file, called, let's say, global decorators, which will contain an array of all of the decor ators that we feel like should be applied globally to storybook. So let's add it like this. And then this global decorators, we will be importing from here. So instead of doing with max with, we call global decorators. And then we will change this to that. And because preview.js applies the project annotations, all of the decorators from global decorators will be applied to every single story.

    [03:53 - 04:26] However, we can still import specific decorators that are not part of the global, which will be used in specific stories. And another interesting aspect of decorators is that according to the documentation, the second argument to a decorator function is the story context . And that story context contains a lot of interesting information about your stories. So let's try this out. Let's say we have now context, and let's just console log this to see how it looks like. We bring up the dev tools. So we can look at the logs. And we see that we logged an object.

    [04:27 - 05:02] The object is context, and that contains a bunch of stuff. So we actually have access to the arcs being passed through our button story, we have access to the component ID to the title, as well as the name, and the art types. So there's a lot of things that you can actually do from here, and be creative about it. You might be able to extract a few arcs and do some extra functionality. You might be able to add a, let's say a heading section to every story where you add some stylized banner with a story name or whatever. So it's pretty interesting to think about it. In our case, we don't necessarily need context because our use case is pretty simple.

    [05:03 - 05:25] However, this will be useful in the next couple lessons. And another important information about decorators is that they are applied in the order of which they were declared. So let's just suppose I have a another decorator, which has a div that says hello world, and then renders the story. As a result, we see that the hello world is actually outside of these boundary.

    [05:26 - 05:59] So if we were to change the order of these decorators, we would see that the hello world is now inside of this boundary. So basically what this means is that the decorators they come from innermost to outermost in the order of which they are defined. This goes for decorators applied in preview and then meta and then story in order of precedence. For now, this component example is really simple. However, if you use decorators to apply theming or access to state management libraries like Redux, the order of which you define them might be pretty important. So it's good to know.

    [06:00 - 06:28] And that's it for the lesson. It's just a recap. We have written decorators that could be applied at the component level at the story level. But also we now have a decorators file, which organizes things correctly for us. And we define the global decorators at the project level with the preview GS. For the next lesson, it doesn't make a lot of sense to keep these global decorators being used. So let's just remove them from here. Still keep this one in case we we want to apply to a specific story. So I'll see you in the next lesson.