storybook: addon-docs not showing all props for styled-component

Describe the bug

Please note this is for the pre-release version as styled-components were not able to be documented until this issue was resolved.

When documenting a styled-component, not all props are rendered out into the props table.

To Reproduce Steps to reproduce the behavior:

  1. Clone the repro repo
  2. npx sb@next upgrade --prerelease
  3. yarn add babel-loader --dev
  4. update the main.js stories glob from ../src/**/*.stories.(ts|tsx|js|jsx|mdx) to ../src/**/*.stories.@(ts|tsx|js|jsx|mdx)
  5. View the button story
  6. The props table is missing the disabled and type props

Expected behavior

The props table should include all props.

Screenshots

image

Code snippets

// Button.tsx
interface Props {
  /**
   * Indicates if the button is disabled
   */
  disabled?: boolean;
  /**
   * Type of button
   */
  type: "submit" | "button" | "reset";
}

/**
 * Button component
  * @returns a button component
 */
export const Button = styled.button.attrs<Props>((props) => ({
  type: props.type
}))`
  ...
`

System:

Environment Info:

  System:
    OS: Windows 10 10.0.18363
    CPU: (8) x64 Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
  Binaries:
    Node: 12.16.1 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.4 - C:\Program Files\nodejs\yarn.CMD
    npm: 6.13.4 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Chrome: 84.0.4147.105
    Edge: Spartan (44.18362.449.0)
  npmPackages:
    @storybook/addon-actions: ^6.0.2 => 6.0.2
    @storybook/addon-docs: ^6.0.2 => 6.0.2
    @storybook/addon-links: ^6.0.2 => 6.0.2
    @storybook/addons: ^6.0.2 => 6.0.2
    @storybook/preset-create-react-app: ^3.1.4 => 3.1.4
    @storybook/react: ^6.0.2 => 6.0.2

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 60
  • Comments: 26 (3 by maintainers)

Most upvoted comments

Ping to maintain the issue

I was actually able to fix this issue simply by renaming my component file names to use .tsx instead of .ts. I was using the .ts extension as there was no JSX used in the file (only using Styled Components).

After this fix, all my props showed up with the component description populated with the JSDoc as well. However, the theme, as and forwardedAs props from Styled Components were shown as well. To remove them, I added this configuration in my .storybook/main.js file:

typescript: {
  reactDocgenTypescriptOptions: {
    propFilter: prop =>
      (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true) && 
      excludedProps.indexOf(prop.name) < 0,
  },
}

I hope this helps someone!

@ebellumat This is the workaround I used without touching the original component:

// Button.stories.tsx

import React from 'react'
import { Meta, Story } from '@storybook/react'

import { Button, ButtonProps } from './Button'

// This wrapper is needed to be able to generate the props table/controls automatically
export const ButtonWrapper = (props: ButtonProps) => (
  <Button {...props} />
)

ButtonWrapper.storyName = 'Button'

export default {
  title: 'Components/Button',
  component: ButtonWrapper,
} as Meta

I think this is the same issue I ran into with low-level styled components:

$ fgrep -e @storybook -e styled -e '"react"' package.json 
    "@storybook/addon-essentials": "^6.0.16",
    "@storybook/react": "6.0.16",
    "react": "16.13.1",
    "styled-components": "5.1.1",

Example/index.js:

import PropTypes from 'prop-types';
import styled from 'styled-components';

export const Example = styled.p`
  background-color: ${props => props.color};
  height: 100px;
  width: 100px;
`;

Example.propTypes = {
  /** background color */
  color: PropTypes.string.isRequired,
};

Example/index.stories.js:

import React from 'react';
import {Example} from '.';

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

export const Default = args => <Example {...args} />;
Default.args = {
  color: 'red',
};

image

If I wrap the component in a dummy wrapper…

import React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';

const _Example = styled.p`
  background-color: ${props => props.color};
  height: 100px;
  width: 100px;
`;

export const Example = args => <_Example {...args} />

Example.propTypes = {
  /** background color */
  color: PropTypes.string.isRequired,
};

…then the documentation and the auto-generated controls work: image

But of course I don’t want to do that, because it adds another level in the React component browser every time I use the component. Dumping the component to the browser console could hint at the root cause: it is an object and not a function that returns react components: image

This is still an issue in “@storybook/react”: “^6.4.17”

@sdalonzo an upvote on the original issue is the best way to help get this fixed (aside from contributing a fix)

I have the same issue with storybook 7.0.6.

My workaround is the following:

import { CSSProp, DefaultTheme } from "styled-components";

export interface StyledComponentsBaseProps {
  as?: keyof JSX.IntrinsicElements;
  css?: CSSProp<DefaultTheme>;
}

export interface Props
  extends StyledComponentsBaseProps,
    HTMLAttributes<HTMLDivElement> {
  color?: "bright" | "dark";
}

export const Component: React.FC<Props> = styled.div<Props>`
  ${({ color = "black" }) => css`
    color: ${color === "bright"
      ? 'white'
      : 'black'};
  `}}
`;

The downside are:

  • you have to type the default props for a styled component and the corresponding html tag
  • if you overwrite the HTML tag with the as prop you don’t have the special props of the specific tag you choose, e.g. “href” tag for anchor

@YuCJ you could do a workaround like:

export const BaseButton = ({ ... }) => ...;
BaseButton.propTypes = { ... };
BaseButton.defaultProps = { ... };

export const Button = styled(BaseButton)...;
Button.propTypes = ...
Button.defaultProps = ...

Then in your stories file:

import { Button, BaseButton } from './Button';

export default {
  title: ...
  component: BaseButton,
  ...
}

export const Story1 = () => <Button {...} />;

Still not working =(

I tried a lot of work arounds and nothing.

I don’t want to write these props on docs manually.

I’m using MDX with Styled components here.

I have tried all of the above, work arounds an none of them work, I have styled components and also am pulling types from a third party lib and my props come through but the third party ones dont? any reason for this?

What worked for me, was removing Story<Props>, so I replaced this:

export const MyStory: Story<Props> = args => <MyComponent {...args} />

With this:

export const MyStory = (args: Props) => <MyComponent {...args} />

I now get the full props table. And MyComponent is a pure styled-component, no need for React wrappers.

👋 Hello there! I’ve written a blog post that references this issue! You can view the applicable excerpt here: Styled Components: If using JS and PropTypes, ArgsTable won’t pull props

GitHub discussion: https://github.com/storybookjs/storybook/discussions/18915

✌️