Auto-load all stories in storybook by storybook-loader

3 min readFeb 26, 2019

It is always said that documentation is as important as source code’s quality.

Without neat and tidy documentations, we’ll even forget how/why/what about the code we wrote couple of months before.

As components library grows bigger and bigger, storybook ( came out to take over the documentation problem. storybook is not new to react engineer.It’s easy enough to create a document site with storybook, and it successfully gained more than 30,000 stars and also being supported well by the community.

It seems that docz ( and docusaurus ( are growing rapidly, but storybook is still one of most competive documentation tools as the big number of community.

By the way, storybook is implementing a new addon to support mdx ( as well. It’s really a good news.

Let’s write a story:

create a TextField.stories.js:

import React from ‘react’;
import { storiesOf } from ‘@storybook/react’;
import WithLabel from ‘./TextField/WithLabel’;
import NumberOnly from ‘./TextField/NumberOnly’;
import Outline from ‘./TextField/Outline’;
storiesOf(‘TextField’, module)
.add(‘WithLabel’, () => <WithLabel />)
.add(‘NumberOnly’, () => <NumberOnly />)
.add(‘Outline’, () => <Outline />);

The problem is that you have to add(‘NewPattern’, () => <NewPattern />) to xxx.stories.js once a new pattern appears.

And of course, if you have multiple components and multiple patterns, this repeat work will become little annoying.

Is there a way to solve this meanless repeat work?

Yes. webpack’s require.context ( is the magic sugar.

require.context can read all files under a folder before compiling.

So TextField.stories.js will look like this:

import React from 'react';
import path from 'path';
import { storiesOf } from '@storybook/react';
const req = require.context('./TextField', true, /.js$/);const stories = storiesOf('TextField', module);req.keys().forEach((fileName) => {
const Component = req(fileName);
stories.add(path.basename(fileName, '.js'), () => <Component />);

And after creating this file, you can concentrate on adding new patterns to TextField folder.

Multiple patterns problem is solved , but not the multiple components problem. You still have to create Button.stories.js, Label.stories.js … one folder one file.

What’s the solution?

Well, maybe you think, just make a folder name array, maintain the array and iterate it when using:

import React from 'react';
import path from 'path';
import { storiesOf } from '@storybook/react';
const folders = [
folders.forEach((folderName) => {
const req = require.context(`./${folderName}`, true, /.js$/);
const stories = storiesOf(folderName, module);req.keys().forEach((fileName) => {
const Component = req(fileName);
stories.add(path.basename(fileName, '.js'), () => <Component />);

But NO! It doesn’t work as you expected.

folderName is a variable, which is decided in compile, but require.context need that folderName before it’s been compiled.

Yes, you CANNOT pass a variable to require.context to relief the duplicated work.

However, you can get all files using require.context and parse them by yourself:

import React from 'react';
import path from 'path';
import { storiesOf } from '@storybook/react';
const reqAll = require.context('./', true, /.js$/);const folderSubkeysMap = getFoldersWithFileKey(reqAll);folderSubkeysMap.forEach(([folderName, keys]) => {
const stories = storiesOf(folderName, module);
keys.forEach((fileName) => {
const Component = reqAll(fileName);
stories.add(path.basename(fileName, '.js'), () => <Component />);

And this time, you’re really free.

To simplify these parsing steps, I wrote a library called


By using this library, you can achieve the same goal simply like this:

import { loadJSStories } from 'storybook-loader';const req = require.context('./');loadJSStories(req);

And of course, you can load markdown files by using loadMDStories:

import { loadMDStories } from 'storybook-loader';
import { doc } from 'storybook-readme';
const req = require.context('./');
const options = {
// decorate md's content
contentFuncList: [
loadMDStories(req, options);

You maybe not only want to display components, but also need to show markdown notes in the panel by storybook addon-notes.

You can use loadJSWithNotesStories. It’ll try to find the markdown file in the same folder which has the same name and add it to storybook’s notes section.

import { loadJSWithNotesStories } from 'storybook-loader';const req = require.context('./');
const options = {
// [optional] you can also addDecorator(withNotes) in config.js
storySubFuncList: [
loadJSWithNotesStories(reqList, options);

For more details, you can access my github repo:

and give me a star if you feel it useful.

Have a nice storybook!