Skip to content

Instantly share code, notes, and snippets.

@shilman
Last active May 28, 2024 17:42
Show Gist options
  • Save shilman/bc9cbedb2a7efb5ec6710337cbd20c0c to your computer and use it in GitHub Desktop.
Save shilman/bc9cbedb2a7efb5ec6710337cbd20c0c to your computer and use it in GitHub Desktop.
Storybook Docs Typescript Walkthrough

Storybook Docs w/ CRA & TypeScript

This is a quick-and-dirty walkthrough to set up a fresh project with Storybook Docs, Create React App, and TypeScript. If you're looking for a tutorial, please see Design Systems for Developers, which goes into much more depth but does not use Typescript.

The purpose of this walkthrough is a streamlined Typescript / Docs setup that works out of the box, since there are countless permutations and variables which can influence docs features, such as source code display, docgen, and props tables.

Step 1: Initialize CRA w/ TS

npx create-react-app cra-ts --template typescript

Step 2: Initialize Storybook w/ TS

cd cra-ts
npx -p @storybook/cli sb init --story-format=csf-ts

Step 3: Install & Configure Docs

yarn add @storybook/addon-docs --dev

Then edit ./.storybook/main.js:

module.exports = {
  stories: ["../src/stories/**/*.stories.(ts|tsx|js|jsx)"],
  addons: [
    "@storybook/addon-actions",
    "@storybook/addon-links",
    "@storybook/preset-create-react-app",
    {
      name: "@storybook/addon-docs",
      options: {
        configureJSX: true,
      },
    },
  ],
};

NOTE: If you're using an older version of Storybook or otherwise prefer .storybook/presets.js, you can use export the value of presets from the above example instead:

module.exports = ["@storybook/preset-create-react-app", ...];

Step 4: Verify Installation

yarn storybook

Then edit the button label in ./src/stories/1-Button.stories.tsx and verify that the story updates in Storybook.

Also verify that there's a Docs tab, and that it shows something reasonable-ish. We'll make it better in the next step.

Step 5: Test Props

Storybook can't load docgen information from pre-built libraries, so to test that aspect out, create a file ./src/stories/Button.tsx:

import React, { FC, ReactNode } from "react";

type ButtonProps = {
  children: ReactNode;

  /**
   * Simple click handler
   */
  onClick?: () => void;
};

/**
 * The world's most _basic_ button
 */
export const Button: FC<ButtonProps> = ({ children, onClick }: ButtonProps) => (
  <button onClick={onClick} type="button">
    {children}
  </button>
);

Then update ./src/stories/1-Button.stories.tsx to import this button instead of the @storybook/react demo button. You should see the props update and also the component documentation show up on the Docs tab.

Step 6: Test MDX

Finally, test that MDX is working.

You already installed docs in Step 3, but now you need to tell Storybook to load .stories.mdx files by editing .storybook/main.js:

module.exports = {
  stories: ["../src/stories/**/*.stories.(ts|tsx|js|jsx|mdx)"],
  // more settings ...
};

Then create ./src/stories/Test.stories.mdx:

import { Meta, Story, Preview, Props } from "@storybook/addon-docs/blocks";
import { Button } from "./Button";

<Meta title="Test" />

Here's some _markdown_!

# Preview

<Preview>
  <Story name="button">
    <Button>hello</Button>
  </Story>
</Preview>

# Props

<Props of={Button} />

You should see a new entry in your Storybook's navigation, a story, and the documentation you wrote in the Docs tab.

NOTE: If you're using an older version of Storybook or otherwise prefer .storybook/config.[jt]s, you can add the stories to your configure statement:

import { configure } from "@storybook/react";

configure(
  require.context("../src/stories", true, /\.stories\.(mdx|[tj]sx?)$/),
  module
);

Notes

The sourceLoaderOptions: null in Step 3 is covering up Storybook issue #7829: Addon-docs: Typescript source support. I'll fix that issue ASAP to complete the walkthrough and update this gist when it's ready.

@johnnyBira
Copy link

@shilman @mrmckeb my Issue was most likely related to me editing tsconfig. The reason I did this was because I needed different settings then the cra settings when transpiling as a library bundle.
After making a separate tsconfig for this purpose and leaving the one generated by cra untouched everything was working as expected.

Thanks you for a super helpful walkthrough 👏

@Faliszek
Copy link

Faliszek commented Feb 14, 2020

Hi,
Thanks a lot for your work, with this gist I was able setup awesome docs pretty quickly!
But Step 5. with Storybook can't load docgen information from pre-built libraries, really bugged me.

I have monorepo, with component and storybook

When I import in storybook component from package

import {Component} @my-repo/my-component
the can't read props, and returns No props found for this component

But when I create dumb file Component.tsx in my storybook/src folder which just 'rexport' my component like

import { Component } from '@my-repop/my-component';
export default Component;

and then i use it in my storybook
import Component from '../Component'

<Props /> component works like a charm.

Can someone explain me this behaviour? Thanks in advance.

Cheers.

@shilman
Copy link
Author

shilman commented Feb 14, 2020

@Faliszek I think what's going on here is that when you import from @my-repo/my-component it's importing from node_modules which is a compiled JS file where the types are all stripped off. When you import from a file in your project, it's smart enough to use the TS version which has types.

@sadi304
Copy link

sadi304 commented Feb 20, 2020

Is anyone facing issue like empty docs page. There is docs tab but without any content. Using it with typescript (storybook-preset)

@shilman
Copy link
Author

shilman commented Feb 20, 2020

@sadi304 if you're using CRA, the CRA preset handles it so don't use the typescript preset.

@sadi304
Copy link

sadi304 commented Feb 20, 2020

I am not using cra either. I am working on a component library.

@mrmckeb
Copy link

mrmckeb commented Feb 20, 2020

@sadi304, are your types in a different file than the components? Are you using the TS docgen loader?

@johnnyBira
Copy link

@shilman I followed your answer to @polRk about this feature but can't figure out what I would need to do to get it to work storybookjs/storybook#9110.

Is this a feature that is in a state of development and not yet released or am I missing something?

@shilman
Copy link
Author

shilman commented Feb 20, 2020

@johnnyBira it’s not even merged yet

@ericclemmons
Copy link

For anyone in a monorepo having issues with Step 1's npx command warning about a missing template, run:

yarn create react-app cra-ts —template typescript

Still trying to figure out a way for the compiled .d.ts files to show up as <Props>. (In a monorepo, Storybook is an additional package with dependencies to the HTML, Vue, and React component libraries)

Storybook can't load docgen information from pre-built libraries

@shilman
Copy link
Author

shilman commented Feb 21, 2020

@ericclemmons that sounds amazing! But before you spend too much time on it, you should know that we’re gonna change the recommendation in 6.0 to use Babel plugin React docgen, now that React docgen itself supports typescript

@Losses
Copy link

Losses commented Feb 23, 2020

Will this plugin support the format of tsdocs? Out team get a great benefit from the IDE integration of tsdocs.

The code looks like this:

export interface IconProps {
  className?: string;
  name: string;
  size?: 'w20' | 'w24';
  color?: 'primary' | 'content';
}

/**
 * Show an icon from out icon-font lib.
 * @param props.className (optional) additional class name for this component.
 * @param props.name The name of the icon, you can find it from `public/resource/icon-font/icon-font.html`.
 * @param props.size The size of the icon, could be 'w20' | 'w24', the default value is `w20`。
 * @param props.color (optional) the color of the icon, could be 'primary' | 'content', the default value is 'content'.
 */
const Icon: React.FC<IconProps> = (props) => {
  const className = cn(styles[`w${props.size}`], styles[props.color || 'primary'], props.className)

  return (
    <i className={className} />
  )
}

And, this what happened inside vscode:
image

@shilman
Copy link
Author

shilman commented Feb 23, 2020

@Losses I don't know the current status of @param. It definitely supports this syntax:

export interface IconProps {
  /** (optional) additional class name for this component. */
  className?: string;
  /** The name of the icon, you can find it from `public/resource/icon-font/icon-font.html`. */
  name: string;
  ...
}

@Losses
Copy link

Losses commented Feb 23, 2020

@shilman Based on my test, currently it don't support tsdocs/jsdocs (aka @param). The format you showed indeed works correctly, but vscode can't show component document anymore.

Maybe I should submit an issue to some repo?

@shilman
Copy link
Author

shilman commented Feb 23, 2020

@Losses Yeah, that sounds like an issue with VSCode 😉

I'm overhauling the props table code for 6.0. After a first version of that's ready, I'd accept a PR supporting the syntax you want.

@Losses
Copy link

Losses commented Feb 23, 2020

@shilman Yeah, btw, both jsdocs/tsdocs and current format used in addon-docs are widely used among developers.

I'll submit a feature request in the future, thanks for your reply!

@sadi304
Copy link

sadi304 commented Feb 23, 2020

@sadi304, are your types in a different file than the components? Are you using the TS docgen loader?

yes. everything is included.

@shilman
Copy link
Author

shilman commented Mar 11, 2020

@egor-xyz please file an issue on the storybook repo! aha it's here: storybookjs/storybook#9896

@eliraz-refael
Copy link

eliraz-refael commented Mar 18, 2020

I could not make this plugin work for me. The only thing I missed from the tutorial is this: npx -p @storybook/cli sb init --story-format=csf-ts

I already had a storybook project with typescript configuration (With react-scripts) I followed the docs over storybook's website.

No matter what I try I keep getting that my components has no props. is that --story-format=csf-ts critical? if so, how would I add it to an existing storybook project?

UPDATE:
I just noticed that it works only if I actually using the props, all the props that are not being used are not showing in the table.

@fionues
Copy link

fionues commented Apr 28, 2020

thank you very much for this walkthrough. It helped me a lot. I set up a project from scratch, just like described here.

But like this I don't get nice descriptions of the prop types in the prop table, but just the type (like 'union' or 'signature' instead of the values of the union and the actual signature). Am I missing something?

I get this:
Bildschirmfoto 2020-04-28 um 17 42 57
but expected this:
propsTable

my dependencies:

    "@types/react": "^16.9.0",
    "@types/react-dom": "^16.9.0",
    "node-sass": "^4.14.0",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-scripts": "3.4.1",
    "typescript": "~3.7.2"
  "devDependencies": {
    "@storybook/addon-actions": "^5.3.18",
    "@storybook/addon-docs": "^5.3.18",
    "@storybook/addon-links": "^5.3.18",
    "@storybook/addons": "^5.3.18",
    "@storybook/preset-create-react-app": "^2.1.1",
    "@storybook/react": "^5.3.18"
  } 

@jackiehluo
Copy link

👋 thanks for this walkthrough! i've been getting this error (it's not a cra app—it's an existing react/typescript app). any idea what the issue might be?

 • Detecting project type. ✓
 • Adding storybook support to your "React" library
     Error: Unsupported story format: csf-ts
    at copyTemplate (/Users/jackieluo/.npm/_npx/23744/lib/node_modules/@storybook/cli/lib/helpers.js:319:11)
    at default (/Users/jackieluo/.npm/_npx/23744/lib/node_modules/@storybook/cli/generators/REACT/index.js:23:3)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)

@shilman
Copy link
Author

shilman commented May 2, 2020

@jackiehluo The storybook CLI has templates for different story formats, e.g. JS vs TypeScript. The typescript coverage is not complete--we have templates for CRA but not necessarily for all frameworks. @yannbf is working on it. Until that's ready, as a workaround you can just leave off that "--story-format csf-ts" and it will use the JS template and you can update your stories by hand.

@fullsnackdeveloper
Copy link

I'm having the same trouble as @fionanueesch. For some reason when I rename "Button.tsx" to "Button.stories.tsx" (moving it to another director) it works as expected.

@shilman
Copy link
Author

shilman commented Jun 11, 2020

Please upgrade to 6.0-beta. Lots of issues solved there!!! @fullsnackdeveloper @fionanueesch

@rxliuli
Copy link

rxliuli commented Dec 1, 2020

Are there any plans to support Proxy?

@fardeen-panjwani-vxlllc

Is there a way to include pages that require authentication?

@ashalfarhan
Copy link

Hi, Thanks a lot for your work, with this gist I was able setup awesome docs pretty quickly! But Step 5. with Storybook can't load docgen information from pre-built libraries, really bugged me.

I have monorepo, with component and storybook

When I import in storybook component from package

import {Component} @my-repo/my-component the can't read props, and returns No props found for this component

But when I create dumb file Component.tsx in my storybook/src folder which just 'rexport' my component like

import { Component } from '@my-repop/my-component';
export default Component;

and then i use it in my storybook import Component from '../Component'

<Props /> component works like a charm.

Can someone explain me this behaviour? Thanks in advance.

Cheers.

Anyone is having a workaround for this issue???

@SalahAdDin
Copy link

What if we want to set the main file in Typescript?

@yannbf
Copy link

yannbf commented Jan 16, 2023

Hey peeps, FYI this gist was created a long time ago and things have changed since. Please find the documentation in https://storybook.js.org/ for reference instead!

@D1no
Copy link

D1no commented Mar 4, 2023

@yannbf cool, maybe link to it. If people (like me) would find that information easily, they wouldn't end up doing google -> this page. Couldn't find anything similar to this information on "storybook.js.org for reference" 😑

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment