Webpack loader to generate docgen information from TypeScript React components. The primary use case is to get the prop types table populated in the Storybook Info Addon.
Example Storybook project
Live Storybook
- Changelog
- Quick Start
- Documenting Components with Storybook
- Loader Options
- Performance
- Alternative Implementation
- Limitations
- Contributing
- Credits
- License
- Add the ability to filter props using a filtering function. Thanks @rkostrzewski. strothj#21
- Bump
react-docgen-typescript
dependency tov1.6.0
:parse can be called with multiple source file paths (thanks to @marionebl PR #91)
upgraded typescript version and fixed parsing comment problem (thanks to @kbukum PR #97)
- Bump
react-docgen-typescript
dependency tov1.5.0
:Remove spread logic.
Support spread default props.
Use folder name if file name is index.
chore(parser): refactor displayName extraction
chore(Parser): read displayName
parse tsconfig.json mirroring TSC’s process
Added support for referenced default props in stateless components
support referenced defaultProps
Extracts default props from stateless components
- Bump
react-docgen-typescript
dependency tov1.2.6
:Fix React.SFC-typed functional components
https://github.com/styleguidist/react-docgen-typescript/commit/e9d57f229b9760967ddc0a746b1c1443f06762b0 - Loader option
setDisplayName
now correctly acceptsfalse
value.
- Use original source text when generating amended code (resolves #7).
The source code generation relies on being able to insert // @ts-ignore
in a few select places and as such requires TypeScript 2.3 or above.
$ npm install --save-dev react-docgen-typescript-loader
or
$ yarn add --dev react-docgen-typescript-loader
IMPORTANT: Webpack loaders are executed right-to-left (or bottom-to-top). react-docgen-typescript-loader
needs to be added under ts-loader
.
Example Storybook config /.storybook/webpack.config.js
:
const path = require("path");
module.exports = (baseConfig, env, config) => {
config.module.rules.push({
test: /\.tsx?$/,
include: path.resolve(__dirname, "../src"),
use: [
require.resolve("ts-loader"),
require.resolve("react-docgen-typescript-loader"),
],
});
config.resolve.extensions.push(".ts", ".tsx");
return config;
};
const path = require("path");
const genDefaultConfig = require("@storybook/react/dist/server/config/defaults/webpack.config.js");
module.exports = (baseConfig, env) => {
const config = genDefaultConfig(baseConfig);
config.module.rules.push({
test: /\.tsx?$/,
include: path.resolve(__dirname, "../src"),
use: [
require.resolve("ts-loader"),
require.resolve("react-docgen-typescript-loader"),
],
});
config.resolve.extensions.push(".ts", ".tsx");
return config;
};
Include the withInfo
decorator as normal.
Reference the addon documentation for the latest usage instructions:
https://github.com/storybooks/storybook/tree/master/addons/info
The Storybook Info Addon is able to populate the component description from your component's documentation. It does this when your story name matches the display name of your component. The prop tables will populate in either case.
In the first example you are able to see above Story Source
the component description. The second example shows a story with a name different from the component. In the second example the component description is missing.
If you have a component named
TicTacToeCell
, then you would have to use something like: storiesOf("...", module).add("TicTacToeCell", ...)
to have the story description come from the component description.
In addition to the description from the component, you may still include story description text using the normal withInfo api.
It is important to export your component using a named export for docgen information to be generated properly.
TicTacToeCell.tsx
:
import React, { Component } from "react";
import * as styles from "./TicTacToeCell.css";
interface Props {
/**
* Value to display, either empty (" ") or "X" / "O".
*
* @default " "
**/
value?: " " | "X" | "O";
/** Cell position on game board. */
position: { x: number, y: number };
/** Called when an empty cell is clicked. */
onClick?: (x: number, y: number) => void;
}
/**
* TicTacToe game cell. Displays a clickable button when the value is " ",
* otherwise displays "X" or "O".
*/
// Notice the named export here, this is required for docgen information
// to be generated correctly.
export class TicTacToeCell extends Component<Props> {
handleClick = () => {
const {
position: { x, y },
onClick,
} = this.props;
if (!onClick) return;
onClick(x, y);
};
render() {
const { value = " " } = this.props;
const disabled = value !== " ";
const classes = `${styles.button} ${disabled ? styles.disabled : ""}`;
return (
<button
className={classes}
disabled={disabled}
onClick={this.handleClick}
>
{value}
</button>
);
}
}
// Component can still be exported as default.
export default TicTacToeCell;
ColorButton.stories.tsx
:
import React from "react";
import { storiesOf } from "@storybook/react";
import { withInfo } from "@storybook/addon-info";
import { action } from "@storybook/addon-actions";
import TicTacToeCell from "./TicTacToeCell";
const stories = storiesOf("Components", module);
stories.add(
"TicTacToeCell",
withInfo({ inline: true })(() => (
<TicTacToeCell
value="X"
position={{ x: 0, y: 0 }}
onClick={action("onClick")}
/>
)),
);
Option | Type | Description |
---|---|---|
skipPropsWithName | string[] or string | Avoid including docgen information for the prop or props specified. |
skipPropsWithoutDoc | boolean | Avoid including docgen information for props without documentation. |
propFilter | function | Filter props using a function. If skipPropsWithName or skipPropsWithoutDoc is defined the function will not be used. Function accepts two arguments: object with information about prop and an object with information about component. Return true to include prop in documentation. https://github.com/styleguidist/react-docgen-typescript#parseroptions |
tsconfigPath | string | Specify the location of the tsconfig.json to use. Can not be used with compilerOptions. |
compilerOptions | typescript.CompilerOptions | Specify TypeScript compiler options. Can not be used with tsconfigPath. |
docgenCollectionName | string or null | Specify the docgen collection name to use. All docgen information will be collected into this global object. Set to null to disable. Defaults to STORYBOOK_REACT_CLASSES for use with the Storybook Info Addon. https://github.com/gongreg/react-storybook-addon-docgen |
setDisplayName | boolean | Automatically set the components' display name. If you want to set display names yourself or are using another plugin to do this, you should disable this option. Defaults to true . This is used to preserve component display names during a production build of Storybook. |
includes | string[] | Converted to an array of regular expressions. Files matching these regular expressions will be processed by the parser. Defaults to ["\\.tsx$"] |
excludes | string[] | See includes. Any file matched by includes will be checked against excludes. Any matching excludes will not be processed by the parser. Defaults to ["node_modules"] . |
There is a significant startup cost due to the initial type parsing. Once the project is running in watch mode, things should be smoother due to Webpack caching.
You can speed up the loading performance by restricting the set of project files which are processed by the parser. It accepts an optional array of includes and excludes as strings (converted to regular expressions). By default includes
is set to ["\\.tsx$"]
and excludes is set to ["node_modules"]
.
Folder structure:
/src/components/
/SimpleButton/SimpleButton.tsx
/SimpleButton/SimpleButton.stories.tsx
Webpack:
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: [
"ts-loader",
{
loader: "react-docgen-typescript-loader",
options: {
includes: ["components.*\\.tsx$"],
excludes: ["stories\\.tsx$"]
}
}
]
}
This plugin uses a Webpack loader to inject the docgen information. There is also a version which works as a Webpack plugin. I will be supporting both versions. The loader version more accurately generates the injected code blocks and should work with all module types but at the cost of a longer initial startup. The plugin version may be faster.
The Webpack plugin version is available here: https://github.com/strothj/react-docgen-typescript-loader/tree/plugin
This plugin makes use of the project: https://github.com/styleguidist/react-docgen-typescript. It is subject to the same limitations.
When extending from React.Component
as opposed to Component
, docgens don't seem to be created. Ref issue #10 (thanks @StevenLangbroek for tracking down the cause).
Doesn't work:
import React from 'react';
interface IProps {
whatever?: string;
};
export default class MyComponent extends React.Component<IProps> {}
Works:
import React, { Component } from 'react';
export default class MyComponent extends Component<IProps> {}
Component docgen information can not be generated for components that are only exported as default. You can work around the issue by exporting the component using a named export.
import * as React from "react";
interface ColorButtonProps {
/** Buttons background color */
color: "blue" | "green";
}
/** A button with a configurable background color. */
export const ColorButton: React.SFC<ColorButtonProps> = props => (
<button
style={{
padding: 40,
color: "#eee",
backgroundColor: props.color,
fontSize: "2rem",
}}
>
{props.children}
</button>
);
export default ColorButton;
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Please make sure to update tests as appropriate.