Boost your design system with Storybook Cartesian

Dotan Nahum
Oct 2, 2018 · 4 min read
Storybook Cartesian
Storybook Cartesian

As part of my investment in DesignOps, I’ve bumped into a common problem with a rather nice solution.

Storybook Cartesian is a library that automatically generates stories for all of your component variants and puts them back in your storybook in a clean and tidy way.

Having a great React component means having it take some properties and do something useful with it. Take a look at this button:

const Button = props =>(
<button
style={{color: props.color}}
enabled={!props.disabled}>
{props.text}
</button>)

To build stories for this component in your design system, you can use some common sense and want to test enabled / disabled, and a couple of colors. But what about empty text? what about a combination of disabled and empty text? does that create anything odd?

Instead of guessing all these combinations, you can generate them with storybook-cartesian.

Storybook cartesian in action
Storybook cartesian in action
Storybook Cartesian in action!

On the one hand, it’s great to be able to click through all of the variants (instead of using knobs to force them out manually), but more importantly, if you have these stories layed out, you can get a massive test coverage with storyshots.

If you’re impatient, there’s a fully working example in the storybook-cartesian repository.

Quick Start

$ yarn add --dev storybook-cartesian

To integrate in your own project, add the following to your stories in your storybook files. Here’s a real life button being exercised to its fullest:

Understanding Cartesian Stories

The general structure for a cartesian story is this:

cartesian(<stories>)
.add(
<seed function>,
<title renderer>,
<component renderer>,
<valid combination filter (optional)>,
<story apply function (optional)>
)

Which gets you this kind of story layout generated automatically (for now the last “All/all variants” is a story discussed in Advanced):

Stories layout
Stories layout
Automatically generated with storybook-cartesian

Your seed function is responsible to generate content in the form of:

Your titleRender function gets an instance of your props and returns a string. This is where you get to build those fancy story titles that will make every generated story super visible.

const titleRender = props => `${props.one} / ${props.check}`

Your storyRender function gets an instance of your props and returns a component. This is where you can just spread the props out and have an easy win, or do something fancy and build out a storyfied component proper.

const componentRender = props => <Button {...props} />

And to make use of all of these with cartesian we can now do:

cartesian(storiesOf('Button/Cartesian'))
.add(
seedfn,
titleRender,
componentRender
)

Last thing to remember — your seedfn is a function. Currently it just returns a static bag of props, but it’s a function for good reason. You can use tools like react-fake-props to generate this seed bag of props automatically as well — without writing any verbatim seed code. In addition you can use this function to fetch content dynamically from a backend.


Validation and Advanced Rendering

Some times not all prop combinations make sense. For example if you have an isLoading and a results props it doesn't make sense to have both true and results populated:

// doesn't make sense
<SearchResults isLoading={true} results={['hello', 'world']}>

For this, we have a valid function that we can add on top of what we’ve seen until now. With it, the following will filter out this invalid combination:

cartesian(storiesOf('Button/Cartesian'))
.add(
seedfn,
titleRender,
componentRender,
props => !(props.isLoading && props.results)
)

The default valid function, if not given, is simply returning true always.

Some other times you might want to customize how stories get created. By default, react-cartesian will add one story per variation. For some components types (such as a button) you might not want to “spend” an entire story.

For example, let’s say you want just one story to contain all cartesian product items.

All variants
All variants

For this, we have another optional function that we can use, that gives you stories and candidates back with which you can do what ever you want:

Try it out!

Storybook Cartesian is a great way to get your design system going. It will allow you to spread out all these UI states that you haven’t considered with no effort at all. You can take a look on Github and you’re welcome to try it out (or submit pull requests!).

Have fun!

Dotan Nahum

Written by

@jondot | CTO at HiredScore. ex-CTO at Como. Hacker. Fullstacker. Big data. Open sourcer.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade