Creating a React component library using Storybook

Bart Waardenburg
7 min readOct 27, 2017

--

An example view from the in progress component library using Storybook

The ANWB is a Dutch company which focusses on a wide variety of consumer services and thus has an equally wide variety of web applications. A recent count by one of my colleagues resulted in roughly 150 web applications currently running in some shape of form on our site. Almost none of those applications reuse each others code to help maintain developer productivity or to present a uniform appearance. We thought it was about time to change that and to start building an easily usable User Interface Component library.

The ANWB Routing application

I’ve been researching and building the library for a couple of weeks now and I thought it was time to share some of the findings I encountered along the way. All in all I can wholeheartedly recommend the following tools to anyone looking for a way to promote UI code reuse at their workplace.

First up the folder structure of the component library:

The structure of the component-libary folder

We wanted to create a system where each component could be versioned independently as we’re expecting to move a lot of apps to this system. Applications should be able to mix and match their components and versions to make working with them as easy as possible. That’s why all components live in their own folders with their own package.json files.

Without further ado let’s explain each of the used tools, the reasoning for using them and some examples or configs.

React

When reevaluating the choice of framework (or none at all) React still came out as the preferred tool of choice for now. It has a really solid community (and company) backing it so continuity is not something to worry about. Besides that due to the massive popularity there are a ton of components available to reuse. Our team already has plenty experience working with the framework and new developers can get up to speed easily due to readily available training material and lots of answers on stackoverflow.

We’ll keep switching to Preact open as an option and maybe look into Skate when it start maturing ( ‘using the platform etc.’ ), but for raw developer speed, functionality and ease-of-use React is the winner for us today.

Flow

When developing React components you’re given three options to enforce the proper usage of props by others (or yourself for that matter).

  1. Proptypes are the original javascript option provided by the React team. I was originally under the impression that it was only usable for React components, but it was pointed out to me that it could be used for runtime type checking any JavaScript. The runtime part is what makes it slightly less viable then the other two options as those options provide a lot of information while developing which proptypes can’t help with.
  2. Typescript is probably the most popular typed version of javascript and has great tooling surrounding it. My personal experience makes me a little less enthusiastic compared with the rest of the community. Somehow it just gets into my way to much with errors I can’t seem to solve when combined with other tools (your miles may vary).
  3. Flow for me is the tool of choice when it comes to providing types to my React components. It’s a big plus for me that it integrates so well with my Babel workflow and that it doesn’t enforce or get in my face as much. It does however help me greatly with preventing bugs and hinting me with autocompletion.
A simple React component using flow to validate the props

What’s the setup like you may ask?

yarn add flow-bin

And even that’s optional as it seems that Storybook (up next) and it’s default babel setup is taking care of the rest.

Storybook

A proper component library needs a set of tools to help build, maintain, share and test. The top contender and winner by a landslide in that department was Storybook for us. The tool is actively developed, uses a lot of great standard configurations and has a thriving add-on eco-system. It was extremely easy to setup and had us building our first components in a mere couple of minutes. The generated documentation using the info add-on, the live tinkering with properties using the knobs add-on and the automagically generated snapshot unit-tests using the storyshots add-on made for a lovely and usable component library.

Storybook at work for our progress component

The config is super easy!

Already using one of our components to decorate our ‘component stories’!

Well, how do you write these stories you may wonder. Well wonder no more:

An example story for the previously shown Progress component

It’s fairly easy to write a story for a new component. You’ll set up a collection of stories by specifying a name and you can add examples of how those components can be used by firing the stories.add() function. In the example above we use withInfo() to decorate the component with a little bit of information and automatically generated prop type documentation (using react-docgen behind the scenes). The withKnobs() decorator and the number() function help generating the slider which can be seen in the right pane of the screenshot. With knobs you can live edit the props of a component from within the browser to see their results.

The final thing I want to share about Storybook is the previously mentioned storyshots add-on. When writing stories storyshots will automatically generate so called snapshot tests for each individual story. A snapshot test works by taking the output of a React component tree (which is basically html) and storing that information when a test is run for the first time. After that each consecutive test-run will compare the newly generated output with the last and will warn you when there are any changes. You can then decide if those changes were intentional or not. Magic right?

Rollup

When it comes to bundling and making the individual React components ready for usage Rollup surfaced as the tool of choice. The only real other contender was Webpack which is a great tool on it’s own and something we might switch to when working with more complex components using dynamic imports. But for now simply rolling up the components for distribution works wonders.

All the needed rollup configuration

We only need to produce a production build since we’re not building the components when developing. Storybook with Webpack will take care of that part behind the scenes. The output target we have set to be a commonjs module, but that’s still something we have to maybe look into in the future.

Lerna

All that is left now is publishing the components to our private registry so everyone in our company can start using them. For that (and maintaining the repository) we’re using Lerna with Yarn workspaces. Lerna is a tool which provides a cli to run commands across multiple packages and Yarn workspaces will help deduping your node_modules folders.

Config is super easy
(I’ve excluded some scripts and all dependencies for readability)

Like I mentioned before each individual component has a package.json file of its own:

The package.json for the already familiar progress component

The main and module fields are used to point to the output and source files respectively. Webpack will be able to use the non-build version when developing so it can do the bundling and optimisations itself and other tools will know to use the commonjs version produced by rollup. Producing the rollup version of the component is the only thing happening in the scripts section here. Clean and easy.

Publishing new versions

Running the lerna publish command with prompt with selecting a new version before publishing for each individual component. And voilà your entire team can start consuming your newly build React components.

Others

Finally other tools we’ve been using which deserve a mention:

  1. Eslint with the fantastic eslint-plugin-jsx-a11y to ensure all our components are written with enforced accessibility guidelines (and valid javascript).
  2. Prettier to help with maintaining readable code and to prevent bikeshedding about code formatting preferences.
  3. Jest to test our code without crazy setup files. It just works, is blazingly fast and has a great developer experience with its interactive watch mode.
  4. Lint-staged with running the above three tools before every commit so no faulty code can ever make it into our git repository (theoretically).
  5. Babel as the final mention. While it’s managed mostly under the hood by Storybook. Babel makes sure all our modern code is working in todays browsers by transpiling where needed with the help of the babel-preset-env preset.

If you’ve got any questions, tips our comments please let me know here or on twitter at @bartwaardenburg. And if this looks like a system you would want to work with know we’re always looking for enthusiastic developers of any skill level at ANWB.

--

--