The life-changing magic of tidying up components with Storybook

Gabriela Gabriel
BlaBlaCar
Published in
9 min readJan 14, 2021

How BlaBlaCar SPA Team creates rich documentation with Storybook 6.0+

Tiding up with Storybook

Building User Interfaces is now more complicated than ever. Layout, logic, performance, internationalization, accessibility should be assembled seamlessly. Thinking about all these attributes in terms of components has made design and development a lot easier to think about.

Components are, as we like to compare at BlaBlaCar, like Lego blocks that can be combined to create bigger elements/structures. An application, for example, is, actually, the simple composition of these smaller UI components.

But how to organize all those Legos in a way that all developers can share and play around with? Let’s put them in a tidy drawer! A special place where it would be easier to find them, to know what components already exist (like a library), what they do, and how to use them with some functional examples.

Storybook is that magical drawer. A popular and fantastic tool that allows frontend developers to build and test these components in isolation. It also has the ability to generate static sites that can be published for documentation and collaboration purposes.

On BlaBlaCar’s SPA Team, we use Storybook to build durable documented UI. Every time a developer needs to create a new page on the application, he/she checks the components available on our ui-library to gather more information about it.

If you are familiar with this development process, you know we have code and documentation separated into different files. A .(j|t)sx for declaring components itself, a .md to write the documentation in Markdown syntax, and a .story.(j|t)sx to declare Storybook stories.

Files architecture

You may be wondering, how come this documentation never goes out of date? Oh, that (my friend) is our goal with updating Storybook to its latest version.

Among developers, we have some adage:

“Code is often the only thing we can really trust”

The Storybook’s version 6.0+ promotes bringing code and documentation even closer with the power of MDX.

MDX is an authorable format that allows writing JSX and Markdown on the same document. You can import real React components and mix them up with your content to better explain how to use them.

example of an MDX file: MDX and JSX together

On top of that, version 6.0 introduces a breaking change on the previous stories.of syntax which leaves us with no other choice but to migrate our components if we want to keep improving our documentation stack. So, no choice, but a great opportunity to improve ui-library documentation and development experience.

Let’s take a look at the goodies that this latest version brings step by step along with how the SPA team implemented it on this migration journey.

What makes good documentation?

As we mentioned earlier, quality documentation is crucial to help developers re-use components from a component library.

To start this journey, let’s step back and take a look at how “good” can be defined: what makes “good” documentation?

The first insights are:

  • Render and code examples
  • Be able to copy/paste code snippets
  • A clear description of the component API (Props)
  • Play/Interact with the component props/render
  • Readable Specifications

The previous version of ui-library was missing some of these important parts. Some components had no specifications, no code snippets, and no ability to copy/paste, nor a clear description of a component API, and so on.

Storybook 5.0 Colors Swatch

Oh! Looks like a messy drawer! Let’s shake the dust off and build cleaner and richer documentation with the brand new DocsPage feature from Storybook.

DocsPage is the new default documentation with the goal to apply best practices when documenting a component. It aggregates stories, text descriptions, properties table listing and description, and code snippets into a single page for each component. And all of that as automated as possible, inferred from source code!

HOW TO GET THERE

We are ready to go! ui-library was already using the package version in which these new features were available as beta but they weren’t applied to the code. The version v5.0 allows both syntaxes to work side by side and buys us time to complete the migration moving component by component at an easier pace until the breaking change on version v6.0.

Unfortunately, even if Storybook provides a migration guide and script, it could not be applied completely like magic on this migration due to some ui-library specificity. Indeed, ui-library needed first, to apply all version 5.0 changes as a pre-requirement to version 6.0!

The common steps to any migration:

  1. Upgrading packages and configuration
  2. Dealing with breaking changes
  3. Updating to current best practices

Let’s look in detail at what has been done.

What has been done

New configuration files

The v5.3+ introduce a new declarative configuration file main.js

Declaration files example from Storybook Documentation

As the name implies, it is the main and most important file where all the configuration will take place: override Webpack configurations, load stories, load addons, and add some custom options for them.

On ui-library Webpack configuration should be overridden to support Typescript. On version v6.0, Typescript support will be built in, so we can remove these configurations from here once we get there;

Since this file also loads all stories, the file stories/index.js that held all manual declarations to load stories isn’t useful anymore and could be deleted! Hooray! 🙌

Preview.js handles Storybook Interface. It applies global parameters and decorators such as Knobs to allow editing components properties dynamically using the Storybook UI.

On ui-library we had Knobs declared on every single file, causing so much noise and repetition.

With the new configuration, we have removed Knobs declaration on every component and declared it as a global decorator. Hooray! 🙌 (x2)

To keep improving the automation on Knobs, another addon was introduced on top of it. SmartKnobs is able to parse Typescript types and present them as properties on Knobs panel allowing to play with a complete list of components’ API. Hooray! 🙌 (x3)

Later on, we will see that SmartKnobs plays such an important role that Storybook has decided to bring this functionality as part of its essentials.

manager.js handles the theming configuration. Storybook comes with dark and light themes now, and also we can apply a custom one. A custom one was our pick! We have created a theme and customized theme.js with BlaBlaCar’s logo, colors, typeface. Theming brings some visual delight even for developers and keeps consistency with our design system, which is what a component library should stand for!! ;) Hooray! 🙌 (x4)

Scaffolding: a component anatomy

Since ui-library has a lot of components (93!!!) to be migrated. A primitive scaffolding tool has been created to support this task.

$ npm run generate
$ component_name

The scaffolding will generate a typical component folder with all the files and imports needed to start a new component or migrate an existing one. Scaffolding establishes consistency and automates oral guidelines and improves the development experience: no need to remember any convention, the script is able to apply it for us.

Here an example of ui-library’s “Component Anatomy”. All components should follow this very same structure :

Scaffolding Files Architecture
  • index.tsx: Exports the Component, its Props and additional item (Enums, Styled-Elements, etc)
  • Component.tsx: The component itself. It imports the styled component declared
  • Component.style.tsx: Declare all the component styles with styled-components
  • Component.test.tsx: Test the file with react-testing-library or with enzyme
  • Component.story.mdx: Write specifications with MDX

By having all the configuration done and also our new component structure, we can now dive deeper into how to write a component story.

MDX, the new syntax: what changes

No more .js/.tsx/.md file to describe a story. With MDX, Markdown and JSX, components can share the same file making specifications easy to write and to read.

DocsPage stories enable auto-generated documentation importing the real React components.

The focus in this brand new way of declaring stories is on documenting instead of any layout/config addition. That said, stories should be clean and as close as possible to the real usage of the component.

Every time DocsPage encounters a code declaration it will be able to be copied and thus, avoid using components on stories that are merely attached to the layout or appearance, they should not be used.

How to declare a DocBlock

Here an example of a Component.story.mdx

  • Meta is an element that situates your component in the Storybook.
  • Story defines a new story (or references an existing one).
  • Canvas frames one (or more stories) and displays their source code. Hooray! 🙌 (x5)
  • <ArgsTable of={Component} /> display an auto-generated properties table from a component’s API based on Typescript types declarations. Hooray! 🙌 (x6)

Some ui-library considerations: styled-components, Props, and Exports

The new stack relies heavily upon proper Typescript type definitions. SmartKnobs and DocsPage read them to generate Knobs and the ArgsTable.

It will require some changes to how ui-library components have been exported/declared.

Starting with index.tsx. It will for now hold all the explicit exports. By reading this file, we already know what the component is exposing to its public API. It will normally export only the Component and its Props.

This is a standard way to make sure all the Component import will come from index no matter which files imported it

export { __COMPONENT_NAME__, __COMPONENT_NAME__Props } from ‘./__COMPONENT_NAME__’
index.tsx

Component.style.tsx No more styles declared in the index file, then. ui-library uses styled-components meaning that when you’re defining your styles, you’re actually creating a normal React component that has its styles attached to it. To make that definition clear, declaring a styled-component has been honored with a dedicated file.

import styled from ‘styled-components’ export const Styled__COMPONENT_NAME__ = styled.div`// Styles go here`
Component.style.tsx

And then this component can be imported in Component.tsx as such

import { Styled__COMPONENT_NAME__ } from ‘./__COMPONENT_NAME__.style’ export const __COMPONENT_NAME__ = ({}: __COMPONENT_NAME
Component.tsx

HANDS-ON

A huge strategy task force was deployed by having 6 people of the team working together in the same week towards this goal! We couldn’t have done it without it! It took us a total of 20 days (4 weeks) of work from set up, configuration, presentation to team members, creating tutorial and documentation, doing internal dojos, and finally migrating all 93 components, component by component.

Mind the steps

Let’s sum up all steps on this migration:

  1. Updating Storybook packages
  2. Applying new configuration files moving it to the new declarative syntax
  3. Picking a component to migrate
  4. Run the component scaffolding generator
  5. Declare styled-components on its own file
  6. Importing styled-component inside a component file declaration
  7. Exporting only component and props from the index file
  8. Moving old tests to test file or writing new tests with react-testing-library
  9. Writing stories with Markdown and JSX (MDX)

📚 TADA!!! You’ve migrated a component from stories.of to MDX!!!

WHAT’S NEXT

Let’s celebrate all those Hoorays! So many changes for the good! The drawer is tidy now. But this first step is more than just better auto-documentation: it’s also the gateway drug towards an outstanding, richly documented design system! We still have a lot of room to keep improving it.

Along with this journey, we have found some Storybook issues that were reported and should be tackled. We still have some updates to make as replacing SmartKnobs with Controls to be as close as possible to Storybook best practices. Also, we have noticed a lack of human-readable specifications and alignment with our Design System guidelines.

Above all, our main goal is to keep improving Storybook as a tool and a workflow to a Component Driven Development mindset and establishing it as a Single Source of Truth of our Design System, because, nevertheless design systems are documentation! In the perfect implementation of a design system, brand, product, design, and tech use it to cover all the facets of the workflow.

Storybook will be a key tool of alignment across teams in the organization, a reference point, resulting in transparency, a well-defined process, and a consistent product to build a seamless user experience.

I hope you have had a “spark joy” moment tidying up with us.

Thanks to those who have helped me to review this article Thomas Salandre, Guillaume Wuip, Florian Eyzat, Michael Cellier, and all the SPA team for working on this project and make it happen!

--

--