storybook: Addon-Docs: Props table won't be generated for TypeScript types if forwardRef used with the default export

Describe the bug If forwardRef used without named export and with only default one, then no props table will be generated.

For example, this:

Button.tsx

import React, { forwardRef } from 'react';

interface ButtonProps {
  /**
   * Sets the button size.
   */
  variant?: 'small' | 'large';
  /**
   * Disables the button.
   */
  disabled?: boolean;
}

const Button = forwardRef<HTMLButtonElement, ButtonProps>(
  ({ disabled = false, variant = 'small', children }, ref) => (
    <button disabled={disabled} ref={ref}>
      {children} {variant}
    </button>
  ),
);

export default Button;

Button.stories.tsx

import React, { FC } from 'react';
import Button from './Button';

export default { title: 'Button', component: Button };

export const Default: FC = () => <Button>I'm a button!</Button>;

Will lead to this result:

image

But if I add export, a props table will be generated. No need to change import from default to named, jus add export.

export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
  ({ disabled = false, variant = 'small', children }, ref) => (
    <button disabled={disabled} ref={ref}>
      {children} {variant}
    </button>
  ),
);

image

Expected behavior A props table should be generated

Packages

{
    "@storybook/addon-actions": "^5.3.5",
    "@storybook/addon-docs": "^5.3.5",
    "@storybook/addon-links": "^5.3.5",
    "@storybook/addons": "^5.3.5",
    "@storybook/preset-create-react-app": "^1.5.1",
    "@storybook/preset-typescript": "^1.2.0",
    "@storybook/react": "^5.3.5"
}

main.js

module.exports = {
  stories: ['../src/**/*.stories.(tsx|mdx)'],
  addons: [
    {
      name: '@storybook/preset-create-react-app',
      options: {
        tsDocgenLoaderOptions: {},
      },
    },
    {
      name: '@storybook/addon-docs',
      options: {
        configureJSX: true,
      },
    },
  ],
};

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 1
  • Comments: 16 (3 by maintainers)

Commits related to this issue

Most upvoted comments

Hi, You are missing the export keyword before the Component’s name. You have to export const {Component} too, as react-docgen-typescript-loader or react-docgen-loader has not added support for forwardRef’s yet.

import React, { forwardRef } from 'react';

interface ButtonProps {
  /**
   * Sets the button size.
   */
  variant?: 'small' | 'large';
  /**
   * Disables the button.
   */
  disabled?: boolean;
}

//Added export here
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
  ({ disabled = false, variant = 'small', children }, ref) => (
    <button disabled={disabled} ref={ref}>
      {children} {variant}
    </button>
  ),
);

export default Button;

I had the same problem with the 6.1.20 version. It turned out you should not use React.xxx reference and directly use the decomposed member xxx:

// does not work
export const Button: React.FunctionComponent<ButtonProps> = props => {...}

// works
export const Button: FunctionComponent<ButtonProps> = props => {...}


// does not work
export const Button3 = React.forwardRef<RawButton, ButtonProps>((props, ref) => {...}

// works
export const Button = forwardRef<RawButton, ButtonProps>((props, ref) => {...}

Moreover, just changing the type while Storybook is running in watch mode does not work. You need to restart the storybook (or force a full recompilation of the file).

If someone got here in search of why props aren’t generated as it did for me, try instead of writing

export default forwardRef(Component)

Do it this way:

const Component = forwardRef((props: Props, ref: Ref<HTMLWhateverElement>) => /* implementation */)

export default Component

If I add an export, I get only two props in the props table: ref and key. Both are not useful to display there. I actually have a whole interface defined that is still completely ignored.

export const FormInputCheckbox = React.forwardRef<Ref, React.PropsWithChildren<IFormInputCheckRadio>>

At least the error is gone, but we’re not there yet.

Thanks @Zunaib , applying the docs-gen at webpack fixed that.

For anybody having this problem, you just need to add a docs gen for TS after you TS loader. Like that:

      {
        test: /\.tsx?$/,
        include: path.resolve(__dirname, '../src'),
        loader: 'awesome-typescript-loader', //any loader you want
      },
      {
        test: /\.tsx?$/,
        include: path.resolve(__dirname, '../src'),
        loader: 'react-docgen-typescript-loader',
      },

Then it worked like a charm! 💃

Screen Shot 2020-01-19 at 12 49 39

Edit: If someone wants a Live Example, please refer to: https://github.com/viniarruda/react-ecommerce/tree/master/packages/design-system

FYI the recommended 6.0 setup (should work in 5.3 too) is ready, and is the default in the most recent versions of both @storybook/preset-typescript and @storybook/preset-create-react-app:

https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#react-prop-tables-with-typescript

I am commenting on all props-related issues to request that you upgrade so we can get this right before release. Thanks!

Also, Args-based props tables are available in 6.0 alpha:

https://gist.github.com/shilman/69c1dd41a466bae137cc88bd2c6ef487