DEV Community

Cover image for Storybook Controls - The easy way
Piyush Kumar Baliyan for AdmitKard

Posted on

Storybook Controls - The easy way

Storybook is an open source tool for building UI components and pages in isolation. It streamlines UI development, testing, and documentation.

Storybook for React offers functionality to control props from a very pretty ui.
Storybook Controls

We will explore these things in this post:

  • Knobs vs Controls
  • The good - React-docgen
  • The bad - More words to type
  • The solution
  • Bonus - Snippets

Till storybook v5, this was achieved using a community plugin Knobs, which is very popular with around ~1m downloads weekly.
Knobs weekly downloads

Knobs weekly downloads

In Storybook v6, the team released Essentials addons:
Storybook essentials

This was in alignment with Storybook's Zero-config initiative (which included out-of-box TS support, essentials addons, and extended support of more frameworks).

Knobs vs Controls

With this storybook migrated from Knobs in v5 to Controls in v5

Knobs

Knobs in v5

Knobs in v5
export const withAButton = () => (
  <button disabled={boolean('Disabled', false)}>{text('Label', 'Hello Storybook')}</button>
);
Enter fullscreen mode Exit fullscreen mode

Controls

Controls in v6

Controls in v6
export default {
  title: 'Button',
  component: Button,
  argTypes: {
    variant: {
      options: ['primary', 'secondary'],
      control: { type: 'radio' }
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

The good

With the controls, storybook can automatically detect props using react doc-gen, and can automatically generate all the controls for you.
React docgen

The bad

For me, some of the controls were not automatically generated due to some of HOCs that we were using (I know, fixing HOCs can fix react docgen as well).

Also, in-case I want to add custom controls, or want to define controls on my own, then the syntax is a little bit more typing over Knobs syntax.

The Solution

Given the new controls syntax, and the ease of use of old Knobs functions, I ended up creating my own wrappers over new controls.

Wrappers

The approach looks like this:

export const select = <T extends any>(options: T[], defaultValue?: T, props: Partial<ArgProps> = {}) => {
  const allProps: Partial<ReturnedArg<T>> = createControlFromProps<T>(props);
  const type = props.type || 'select';

  allProps.defaultValue = defaultValue || options[0];
  allProps.control = { type, options };
  return allProps;
};
Enter fullscreen mode Exit fullscreen mode

So basically, I took input in knobs format, and returned in controls format.

Here is the full file with these controls:

  • select
  • boolean
  • text
  • number
  • obj
  • action

Usage

With this, the usage looks like:

const argTypes = getArgs<InputProps>({
  label: text('Name'),
  size: select(['small', 'medium', 'large']),
  fullWidth: boolean (false),
  onChange: action('change'),
});
Enter fullscreen mode Exit fullscreen mode

Here is the full code with Input Stories:

Bonus - Snippets

An added bonus will be, create a snippet for a story, and next time have a story ready to be served with few key-strokes.

Discussion (0)