I've got a component, 'Dialog', that renders a modal dialog box basically, when a user clicks on a link or button to invoke/open the dialog. I'm building a storybook component for the Dialog component, and so I need to be able to have a clickable HTML element (anchor tag or button, preferably anchor tag) and open the Dialog component when that clickable HTML element is clicked. I don't know how to go about this in Storybook.
Here is my storybook element as it exists so far:
const Template: ComponentStory<typeof Dialog> = (args) => <Dialog {...args} />;
export const Regular = Template.bind({});
Regular.args = {
type:"regular",
show: false,
children: "Content of Dialog Box",
dismissable: true,
classNames: "",
maxWidth: "1000px",
displayBoxShadow: true,
renderOnLoad: false,
}
An example of an implementation of this component/story would be a Log In button that, when clicked, would render a slide-out dialog with appropriate fields (children). I'm trying to implement the Dialog part of the story, as the Dialog component is invoked when another HTML object on page is clicked/interacted with.
Basically, a Storybook story can be any React component and is not limited to being the bare component that you're show-casing. Simply create a thin wrapper component around your real story with a button:
const Template: ComponentStory<typeof Dialog> = (args) => {
const [open, setOpen] = useState(false)
return (
<>
<Button onClick={ () => setOpen(true) }>
Open dialog
</Button>
<Dialog
{ ...args }
show={open}
onClose={ () => setOpen(false) }
/>
</>
)
}
You can use the same pattern to extend the experience of your Storybook components with more real-world contexts than just the plain component itself.
Full toy example working fine in Storybook 6.4.22:
import React, { FC, useState } from 'react';
import { Meta, Story } from '@storybook/react/types-6-0';
import { Button, Dialog } from "@material-ui/core";
interface TestProps {
open: boolean
text: string
onClose: () => void
}
const Test: FC<TestProps> = props => (
<Dialog open={ props.open } maxWidth={ "lg" } fullWidth onClose={ props.onClose }>
{ props.text }
</Dialog>
)
export default {
title: 'Test',
component: Test
} as Meta;
const Template: Story<Omit<TestProps, "open" | "onClose">> = props => {
const [ open, setOpen ] = useState(false)
return (
<>
<Button onClick={ () => setOpen(true)}>Click me</Button>
<Test open={ open } onClose={ () => setOpen(false) }text={ props.text }/>
</>
)
}
export const ExampleStory = Template.bind({});
ExampleStory.args = {
text: "This is an example"
};
If something is not working in your example, then there is some other problem not related to this method of building a story. Try to generalize from it; start with a simpler component and make it work and take it step by step.