Storybook v7 and v8 not displaying React component markup on "Show code"

814 views Asked by At

I have looked around for quite a long time now, checking similar posts here, Storybook documentation, their GitHub posts, etc, to no avail. Since we upgraded first to v7 and then v8, the "Show code" tab on the doc page isn't displaying the React component markup that's part of said story. All that's displayed are the args used to render the story.

Taking a very simple story, based on an also very simple component (functional, using TypeScript):

Component:

import classNames from 'classnames';
import { memo, MouseEvent } from 'react';

import { decapitalizeFirstLetter } from '@helpers/stringHelper';

import { PadlockIcon } from '@icons';

import styles from './AccessControlIndicator.less';
import Msg from './AccessControlIndicator.msg';
import { Access } from './types';

function AccessControlIndicator({
    access,
    className,
    'data-testid': testId = 'AccessControlIndicator',
    displaySurround = false,
    isReadOnly = false,
    onClick,
}: {
    access: Access;
    className?: string;
    'data-testid'?: string;
    displaySurround?: boolean;
    isReadOnly?: boolean;
    onClick?: (e: MouseEvent) => void;
}) {
    let icon = null;

    switch (access) {
        case Access.None:
        case Access.Restricted:
        case Access.RestrictedAuto:
            icon = <PadlockIcon className={styles.icon} />;
            break;
        case Access.All:
        default:
            icon = null;
            break;
    }

    return (
        <button
            className={classNames(
                styles.root,
                displaySurround && styles.surround,
                isReadOnly && styles.readOnly,
                className,
            )}
            data-state={access}
            data-testid={testId}
            disabled={isReadOnly}
            onClick={!isReadOnly ? onClick : undefined}
        >
            {icon}
            <span className={styles.label}>
                <Msg s="label" />
            </span>
            <span className={styles.access}>
                <Msg s={decapitalizeFirstLetter(access)} />
            </span>
        </button>
    );
}

export default memo(AccessControlIndicator);

Story:

import { Meta, StoryObj } from '@storybook/react';

import AccessControlIndicator from './AccessControlIndicator';
import { Access } from './types';

const meta: Meta<typeof AccessControlIndicator> = {
    component: AccessControlIndicator,
    title: 'AccessControlIndicator',
    argTypes: {
        access: {
            options: Object.keys(Access),
            mapping: Access,
            control: {
                type: 'inline-radio',
            },
        },
    },
};

export default meta;

type Story = StoryObj<typeof AccessControlIndicator>;

const defaultArgs = {
    access: Access.None,
    displaySurround: false,
    isReadOnly: false,
};

export const Default: Story = {
    args: defaultArgs,
};   

What's displayed on the "Show code" doc:

Storybook screenshot

Snippet from main.ts:

addons: [
    '@storybook/addon-a11y',
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
    '@storybook/addon-links',
    'storybook-addon-pseudo-states',
    '@storybook/addon-webpack5-compiler-babel'
],
core: {},
docs: {
    autodocs: true,
},
framework: {
    name: '@storybook/react-webpack5',
    options: {
        builder: {
            fsCache: true,
            lazyCompilation: false,
        },
    },
},

Snippet from preview.ts:

docs: {
    source: {
        language: 'tsx',
    },
},

I would expect to see the generated React markup so other developers could just copy + paste it if they wish to do so.

What am I missing here?

2

There are 2 answers

1
miklosz On

I've managed to reproduced that case and it looks like all you need to do to show the JSX code is to remove type: 'code' from here:

 docs: {
      source: {
          language: 'tsx',
      },
  },
1
Sebastian Meier On

I got the same problem and found out that decorator functions like memo can break the type chain so that the prop types could not be infered correctly.

See this issue for more context: https://github.com/storybookjs/storybook/issues/21192

If I only used memo or forwardRef on a component it worked with the newest version (7.6.7). But if both were used on a component it still didn't work for me.

After some fiddling I found a way that worked with both:

export const FormElement = memo<FormElementProps>(forwardRef(FormElementComponent));

The trick was to provide the props type as a generic type to memo.

Note that I have only validated this to work with Vite and the issue also mentions Vite explicitly, so Webpack might behave differently.