What makes up a Story?
Let's learn about the very basics of Storybook stories
Now that we have Storybook installed in our project, let's understand what's going on with the examples that it came with.
If you don't have Storybook running yet, make sure to run it with:
Component Story Format (CSF)#
Storybook supports Component Story Format (CSF), an open standard based on ES6 modules which was introduced in Storybook 6.0 as the main way to write stories.
In CSF, stories and component metadata are defined as ES Modules. Every component story file consists of a required default export and one or more named exports.
The default export is what we call Meta, the metadata that describes and configures a component. This is the place where you can set the title, which will be shown in the list of stories, or set extra configuration, which can be used by addons.
Let's start by adding the following:
This is telling Storybook to display
Example/Button in the sidebar. Storybook uses the property
component to read metadata about the component, which is important internally and also for a few addons. The
ComponentMeta type automatically infers the props from the
Button component and provides autocompletion for args and argTypes. This is going to be useful soon, we'll circle back to that.
The second piece that a story file needs is a named export. Storybook expects the functions that you export in a story file to represent a state of a component, and that's what we call a story. The story is function that renders the component and optionally has annotations, like args:
As a result, we can see that in Storybook, we have Example/Button on the sidebar, and it presents four stories, one for each named function in the file. This is a great way for developers and designers to understand the possible states of our component!
Let's add a new story to this file. Let's say we want a story to represent the Button with a red background. We create a new named export called
Red, which clones the
Template defined previously, and adds args for the props we want:
We should now have a new story for that visual state in Storybook. Nice!
What about args?#
Args is a concept in Storybook that represents data which can be passed around. This helps us create a master template that can be reused in every story, where each story clones that template and just sets different args. Let's look at the
Template function again:
Storybook will make sure that the args we set for the
Red story will be passed down to that render function. You could think of them as props. Storybook comes with an addon called Controls, which detects the args for a given story and provides a panel where you can tweak with them.
And what about argTypes?#
Each of these args have types (e.g. string, boolean, etc.), and the Controls addon uses these types to provide you the correct element in its panel. These types are called argTypes, and they are automatically processed by Storybook using the
Component declared in the Meta (which is why it's important to declare
Component in default export!).
However, there are cases in which you want something more complex in the Controls panel, like
backgroundColor being a color picker rather than a string field, like
label. In scenarios like these, you can define argTypes manually to override the default behavior of controls. This was actually already done in this file, and you can see it in the Meta:
When setting argTypes in the Meta level, it will be applied to every story. You can also set argTypes to a story level. Let's make the argType of the
Red story contain a radio group with a few color as options:
We notice that the panel now updates with the set of colors we defined:
Args have a cascading behavior#
In Storybook, most of the properties can be set in a story level but also in a component level, like you just saw with argTypes. In every Button story, we see
label: 'Button' being repeated. If you're sure that property should always be applied to every story, you can set that arg at the component level instead.
In order to set properties at the component level, you add them to the Meta (the default export). These properties will then be applied to every single story in your stories file. To reuse common args, all you have to do is add the
args property to the Meta.
Applying args in a component level#
Given that information, we can move the
label arg that is defined in every story to be set in the Meta instead, and remove it from every story as it won't be necessary anymore:
The result will be the same, but you won't ever need to pass down the properties manually like we did before. Just keep in mind that you won't always want properties defined in a component level, so there are times that it's best to define per story basis.
What happens to complex args?#
Args are cascading, so they will be sent down to every story and merged with the
args set in those stories. This means that you can override a single key of a complex object, and it will retain the rest of the properties defined at the component level.
Let's look at an example to visualize this behavior better:
As you noticed, we used two types from
@storybook/react: ComponentMeta and ComponentStory.
These types not only give you autocompletion for
Story attributes, but they also automatically infer the props of components passed into the generics and reflect those types in the
args property. This is great because this way you don't need to export the type of props of your component just to satisfy Storybook!
We see that the
ComponentStory type is only defined in the
Template function, but it's inferred correctly in any function that clones the
Template. This is only possible in projects that contain either
strictBindApplyCall modes set to true in their
tsconfig.json file. This example project already has this configuration, so you don't need to worry about it, but if you end up not having type inference in any other project, this might be the reason.
The Introduction page is a special example that shows that Storybook can also handle MDX files for documentation purposes. This means you can write markdown and React components in the same file. It's a great way to write documentation, as well as onboarding pages with helpful resources, just like the Introduction page illustrates. It also has concepts of
Story, but they are written differently. Most of the concepts we will see in this course (parameters, decorators, etc.) can be applied to MDX as well.
An important feature in Storybook is called decorator. In the next lesson, we will learn how to add extra markup/functionality to components by creating our own decorators.