storybook: Typescript extended props not show v6

Describe the bug Define typescript props for component with extending other props, doesn’t show the extended props.

For example a component with

interface TProps extends ComponentPropsWithoutRef<"input"> {
  label?: string;
  state?: InputState;
  helper?: string | React.ReactElement;
}

export const TextField = forwardRef(
  (
    { label, placeholder, state, helper, ...rest }: TProps,
    ref: Ref<HTMLInputElement>
  ) => (
    ...
  )
);

Produces the following

Screenshot 2020-08-19 at 10 55 40

Expected behavior Its suppose to show all the props valid for the component such as type, max, min e.t.c

System:

Environment Info:
  Binaries:
    Node: 14.2.0 - ~/.nvm/versions/node/v14.2.0/bin/node
    Yarn: 1.22.4 - /usr/local/bin/yarn
    npm: 6.14.7 - ~/.nvm/versions/node/v14.2.0/bin/npm
  Browsers:
    Chrome: 84.0.4147.125
    Firefox: 77.0.1
    Safari: 13.1.2
  npmPackages:
    @storybook/addon-docs: ^6.0.6 => 6.0.6 
    @storybook/addon-essentials: ^6.0.6 => 6.0.6 
    @storybook/addon-knobs: ^6.0.6 => 6.0.6 
    @storybook/addon-links: ^6.0.6 => 6.0.6 
    @storybook/addon-notes: ^5.3.19 => 5.3.19 
    @storybook/addon-storysource: ^6.0.6 => 6.0.6 
    @storybook/addon-viewport: ^6.0.6 => 6.0.6 
    @storybook/addons: ^6.0.6 => 6.0.6 
    @storybook/preset-create-react-app: ^3.1.4 => 3.1.4 
    @storybook/react: ^6.0.6 => 6.0.6

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 19
  • Comments: 40 (8 by maintainers)

Commits related to this issue

Most upvoted comments

Maybe it a little bit tricky but I found temporary solution to generate only material ui props and ignore all of HTML props.

module.exports = {
  stories: ["../src/**/*.stories.tsx"],
  // Add any Storybook addons you want here: https://storybook.js.org/addons/
  addons: ["@storybook/addon-links", "@storybook/addon-essentials"],
  typescript: {
    check: false,
    checkOptions: {},
    reactDocgen: "react-docgen-typescript",
    reactDocgenTypescriptOptions: {
      shouldExtractLiteralValuesFromEnum: true,
      propFilter: (prop) => {
        return prop.parent
            ?  prop.parent.name !== 'DOMAttributes' && prop.parent.name !== 'HTMLAttributes' && prop.parent.name !== 'AriaAttributes'
            : true;
      },
    },
  },
}

Currently we’re using Storybook 6.2.9 with Material UI 4.12.0 and the below configuration works flawlessly for us. It renders all the MUI props properly and ignores all the default HTML props. The two key changes for us were the propFilter and allowSyntheticDefaultImports options. Hope this helps some of you!

module.exports = {
  stories: ["../src/**/*.stories.@(ts|tsx|js|jsx)"],
  addons: ["@storybook/addon-links", "@storybook/addon-essentials"],
  typescript: {
    check: true,
    reactDocgen: "react-docgen-typescript",
    reactDocgenTypescriptOptions: {
      shouldExtractLiteralValuesFromEnum: true,
      propFilter: (prop) =>
        prop.parent
          ? /@material-ui/.test(prop.parent.fileName) || !/node_modules/.test(prop.parent.fileName)
          : true,
      compilerOptions: {
        allowSyntheticDefaultImports: false,
      },
    },
  },
}

I’m having the same problem right now, using the material ui, is anyone working on it?

It seems like just having this works, so it must some misconfiguration internally

typescript: {
    reactDocgen: 'react-docgen-typescript',
    reactDocgenTypescriptOptions: {
    }
  }

Try adding this to main.js:

  typescript: {
    reactDocgen: 'react-docgen-typescript',
    reactDocgenTypescriptOptions: {
      compilerOptions: {
        allowSyntheticDefaultImports: false,
        esModuleInterop: false,
      },
    }
  }

Hey folks, here’s an updated example repo for the material UI recipe to help you on your way.

If you have more questions, let me know and i’ll work on making it clearer

https://stackblitz.com/edit/github-ju9knk?file=.storybook/preview.ts

@Integrayshaun — Mind looking into this? It appears the MUI recipe doesn’t work for all setups?

If someone here can provide a simplified reproduction (https://storybook.new is great for this), that would be a big help. Thanks!

This still happens and since there’s no way determining the cause, this is rather frustrating. I checked with all configurations shown above, and nothing works as expected (1) props are shown, 2) with their correct control types and 3) possible values) - since MUI is (by far) the largest React component library, this is something really worth being investigated / documented, because the docs don’t work 😭

If anyone is looking for a solution working with ant-design & react-docgen-typescript. The following solves the issue:

  1. In the component level, redeclare the Props even if empty, “redeclare” the component so docgen can infer the propTypes (see example)
// Alert.tsx
import type { AlertProps as AntAlertProps } from 'antd/es/alert';
import AntAlert from 'antd/es/alert';

import { FC } from 'react';

export interface Props extends AntAlertProps {}

const Alert: FC<Props> = ({ ...props }: Props) => {
  return <AntAlert {...props} />;
};

export default Alert;
export type { Props as AlertProps };

  1. Add the following configuration to filter in antd props (node_modules is filtered out by default)
 reactDocgen: 'react-docgen-typescript',
    reactDocgenTypescriptOptions: {
      // By default react-doc-gen-typescript filters node_modules type, this includes antd types
      tsconfigPath: '../tsconfig.json',
      propFilter: (prop: any) => {
        const res = /antd/.test(prop.parent?.fileName) || !/node_modules/.test(prop.parent?.fileName);
        return prop.parent ? res : true;
      },
      // The following 2 options turns string types into string literals and allows
      shouldExtractLiteralValuesFromEnum: true,
      savePropValueAsString: true,
      shouldRemoveUndefinedFromOptional: true,
    },

did anyone tried this in Mui 5. I have added additional properties in theme like below

declare module '@mui/material/styles' {

    interface TypographyVariants {
      body14: React.CSSProperties;
      body14b: React.CSSProperties;
    }
 
    // allow configuration using `createTheme`
    interface TypographyVariantsOptions {
      body14?: React.CSSProperties;
      body14b?: React.CSSProperties;
    }
  }
  
  // Update the Typography's variant prop options
  declare module '@mui/material/Typography' {
    interface TypographyPropsVariantOverrides {
      body14: true;
      body14b: true;
    }
  } 

I can see and use the additional variants through the code, but not in storybook

I am using Node: 14.7.0 npm: 8.0.0 yarn: 1.21.1

React: 17 storybook: 6.5.0-alpha

The configuration from @mstosio works for me.

I however also need to create named exports for mui components instead of a default export (this is mentioned on the Storybook TypeScript docs as well).

So I create a file

import Button, { ButtonProps } from '@mui/material/Button';

export const MyButton = ({ ...props }: ButtonProps) => <Button {...props} />;

And then import the MyButton in the story. I’m using the same setup as @bastiW for writing stories. Now I get the correct props displayed in the Docs tab.

I hope this helps.

Having the same problem here

It seems like just having this works, so it must some misconfiguration internally

typescript: {
    reactDocgen: 'react-docgen-typescript',
    reactDocgenTypescriptOptions: {
    }
  }

Personally, it only seemed to work for me with this configuration. Having the additional two booleans in there would break it. Unfortunately, having this new config brings in the props I wanted, but it wrecks some other controls I have (such as limiting another prop to a couple of options).

reactDocgen: “react-docgen-typescript”, reactDocgenTypescriptOptions: { shouldExtractLiteralValuesFromEnum: true, propFilter: (prop) => { return prop.parent ? prop.parent.name !== ‘DOMAttributes’ && prop.parent.name !== ‘HTMLAttributes’ && prop.parent.name !== ‘AriaAttributes’ : true; }, },

Screenshot 2024-03-08 at 1 19 39 > },

Screenshot 2024-03-08 at 1 19 55 Screenshot 2024-03-08 at 1 20 29

mstosio

@mstosio thanks. It helps me, but it adds an undefined value each time. Is there a solution to prevent this undefined value? @developerdanwu @ivanbanov @andresdsep @Quadriphobs1 @dirkvanvugt

@adirzoari try add shouldRemoveUndefinedFromOptional: true to ur config

I am having a similar problem to @krishnans with my own extended MUI 5 Theme I extended my Theme as instructed in the MUI docs and can use the custom color in the code but the dropdown control in Storybook doesn’t show the color I added as a pickable value.

I extended my theme like this:

import '@mui/material/styles';
import '@mui/material/Button';

declare module '@mui/material/styles/createPalette' {
    interface Palette {
        myCustomColor: Palette['primary'];
    }
    interface PaletteOptions {
        myCustomColor?: PaletteOptions['primary'];
    }
}

declare module '@mui/material/Button/Button' {
    interface ButtonPropsColorOverrides {
        myCustomColor: true;
    }
}

My Storybook main.js file looks like this:

module.exports = {
  stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
  ],
  framework: "@storybook/react",
  core: {
    builder: "@storybook/builder-webpack5",
  },
  typescript: {
    check: false,
    checkOptions: {},
    reactDocgen: "react-docgen-typescript",
    reactDocgenTypescriptOptions: {
      allowSyntheticDefaultImports: false, // speeds up storybook build time
      esModuleInterop: false, // speeds up storybook build time
      shouldExtractValuesFromUnion: true,
      shouldExtractLiteralValuesFromEnum: true, // makes union prop types like variant and size appear as select controls
      shouldRemoveUndefinedFromOptional: true, // makes string and boolean types that can be undefined appear as inputs and switches
      savePropValueAsString: true,
      propFilter: (prop) =>
        prop.parent ? !/node_modules/.test(prop.parent.fileName) : true,
      skipPropsWithoutDoc: false,
      skipChildrenPropWithoutDoc: false,
      tsconfigPath: '../tsconfig.json',
    },
  },
};

And my Button.tsx component file looks like this:

import * as React from "react";
import { Button as MaterialButton } from "@mui/material";
import type { ButtonProps as MuiButtonProps } from "@mui/material";

export interface ButtonProps extends MuiButtonProps {
  label: string;
  onClick: React.MouseEventHandler<HTMLButtonElement>;
}

export const Button: React.FC<ButtonProps> = (props: ButtonProps) => {
  const { label } = props;
  return <MaterialButton {...props}>{label}</MaterialButton>;
};

With this result, where myCustomColor is not shown in the color dropdown options: image

I am using: node: 18.14.0 npm: 9.3.1 react: 18.2.0 typescript: 4.9.5 @storybook/react: 6.5.16

I tried using this and it works for module augmentation. The key is the include option below. My declaration file is named styles.d.ts. You have to include it for storybook to take into account the augmented styles. Hope it helps someone

const config: StorybookConfig = {
  typescript: {
    check: false,
    reactDocgen: 'react-docgen-typescript',
    reactDocgenTypescriptOptions: {
      include: ['**/**.tsx', 'src/themes/styles.d.ts'],
      shouldExtractLiteralValuesFromEnum: true,
      skipChildrenPropWithoutDoc: false,
      shouldRemoveUndefinedFromOptional: true,
      tsconfigPath: './tsconfig.json',
      compilerOptions: {
        allowSyntheticDefaultImports: false,
        esModuleInterop: false,
      },
      propFilter: (prop) =>
        prop.parent
          ? /@material-ui/.test(prop.parent.fileName) ||
            !/node_modules/.test(prop.parent.fileName)
          : true,
    },
  },
...
};

@yarinsa thanks for solution

I am having a similar problem to @krishnans with my own extended MUI 5 Theme I extended my Theme as instructed in the MUI docs and can use the custom color in the code but the dropdown control in Storybook doesn’t show the color I added as a pickable value.

I extended my theme like this:

import '@mui/material/styles';
import '@mui/material/Button';

declare module '@mui/material/styles/createPalette' {
    interface Palette {
        myCustomColor: Palette['primary'];
    }
    interface PaletteOptions {
        myCustomColor?: PaletteOptions['primary'];
    }
}

declare module '@mui/material/Button/Button' {
    interface ButtonPropsColorOverrides {
        myCustomColor: true;
    }
}

My Storybook main.js file looks like this:

module.exports = {
  stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
  ],
  framework: "@storybook/react",
  core: {
    builder: "@storybook/builder-webpack5",
  },
  typescript: {
    check: false,
    checkOptions: {},
    reactDocgen: "react-docgen-typescript",
    reactDocgenTypescriptOptions: {
      allowSyntheticDefaultImports: false, // speeds up storybook build time
      esModuleInterop: false, // speeds up storybook build time
      shouldExtractValuesFromUnion: true,
      shouldExtractLiteralValuesFromEnum: true, // makes union prop types like variant and size appear as select controls
      shouldRemoveUndefinedFromOptional: true, // makes string and boolean types that can be undefined appear as inputs and switches
      savePropValueAsString: true,
      propFilter: (prop) =>
        prop.parent ? !/node_modules/.test(prop.parent.fileName) : true,
      skipPropsWithoutDoc: false,
      skipChildrenPropWithoutDoc: false,
      tsconfigPath: '../tsconfig.json',
    },
  },
};

And my Button.tsx component file looks like this:

import * as React from "react";
import { Button as MaterialButton } from "@mui/material";
import type { ButtonProps as MuiButtonProps } from "@mui/material";

export interface ButtonProps extends MuiButtonProps {
  label: string;
  onClick: React.MouseEventHandler<HTMLButtonElement>;
}

export const Button: React.FC<ButtonProps> = (props: ButtonProps) => {
  const { label } = props;
  return <MaterialButton {...props}>{label}</MaterialButton>;
};

With this result, where myCustomColor is not shown in the color dropdown options: image

I am using: node: 18.14.0 npm: 9.3.1 react: 18.2.0 typescript: 4.9.5 @storybook/react: 6.5.16

@natac13 the propFilter config option is a function, so you should be able to do something tricky there to get only the props you want

Try adding this to main.js:

  typescript: {
    reactDocgen: 'react-docgen-typescript',
    reactDocgenTypescriptOptions: {
      compilerOptions: {
        allowSyntheticDefaultImports: false,
        esModuleInterop: false,
      },
    }
  }

This suggest is working for me, however it exposes every HTML prop as well, making the storybook ui unusable since each component now has close to 300 props. Is there a way to stop the extending at the MUI package and no further??