adjoe Engineers’ Blog
 /  Frontend  /  Writing Stories with Storybook to Visualize React Dashboard Components
decorative purple image with colorful elements
Frontend

Writing Stories with Storybook to Visualize React Dashboard Components

In my last article, I explained how your codebase should look in order to seamlessly integrate and use Storybook to document and interact with your components. I also took you through the process of how we integrated Storybook in our new dashboard project, explained how to solve common integration problems, and demonstrated how to automatically upload your documentation to Chromatic, Storybook’s own hosting service.

In this article, I’ll explain the process of writing stories with Storybook for both simple components, like buttons, and more complex state-based components, like filters and dropdowns.

What Is a Story?

When we talk about writing stories with Storybook, a story describes and visualizes a component’s specific state. A component can have multiple stories, based on which states the component can support. Different stories are normally used to show how the component transforms based on which properties are given to it. 

Screenshot of a button story with four substories in Storybook in article about writing stories with Storybook

A story itself has two views: Canvas and Docs.

The Canvas view shows the single story with controls below it. With these controls, you can set all of the component’s properties. This view can also be used to interact with the component. You can change the size of the page to see media queries in action, zoom in and out, switch to dark mode, show the grid, and more.

 The Canvas view also supports various add-ons you can install for your Storybook. You can find a ton of different add-ons here.

Screenshot of the Canvas page of a Button story in Storybook

The Docs view is the documentation page of the component.

Here, you can view the written description of the component. You’ll see a list of all supported properties, as well as prop comments set in the code to explain these. 

The Docs view will show all stories on one page, and you can also view code examples for integration.

Screenshot of the Docs page of a button story in Storybook
Screenshot of the substories in the Docs page of a button story in Storybook
Screenshot of the code example of a button story in Storybook

How Do I Write a Story for a Simple Component?

Storybook provides you with a clear structure of how a story should look like.

The story exports a default object typed as a ComponentMeta, which includes the field’s title and component. The title is responsible for the placement of the story in your Storybook. A title string “Common/Button” will create the component story under the folder “Common” entitled “Button.” In the component field, you pass the actual component to render as a React ComponentType.


Then you can create a template, which is the actual component-rendering function. It will return JSX, which will be used to render the component in the story, passing the properties as arguments. This template can return anything you want and is also where you’ll add the necessary logic or state for more complex components later on. For example, you could wrap your button component in a box here and give it a different background, if you want.


Lastly, the actual stories will be created by binding your template to ComponentStory constants.With this, you can create any number of stories for your component and change the arguments of the template according to your needs.

Let’s use a simple component as an example – a simple wrapper of the MUI button.

interface IButtonProps {
 variant: 'text' | 'outlined';
 onClick: () => void;
 children: React.ReactNode;
}
export const MyButton: FC<IButtonProps> = ({ variant, onClick, children }) => (
 <Button variant={variant} onClick={onClick}>
   {children}
 </Button>
);

Out of this component, you can easily create two stories that show different variants.

First, create a new file next to the component and name it “Button.stories.tsx.” Then, create your default export.

export default {
 title: 'Common/Button',
 component: MyButton,
} as ComponentMeta<typeof MyButton>;

In TypeScript, you have to make sure that you type the object correctly and add the typeof component as a generic.

Next, add the template. In this case, it renders the button with a simple text as the child and passes the arguments to it with prop spreading.

const Template: ComponentStory<typeof MyButton> = args => (
 <MyButton {...args}>Button</MyButton>
);

And then you can define your stories with bindings by setting the variant in the args to what you need. The onClick definition is in this case not necessary – you can just assign a function that does nothing, or you could make a console log.

export const DemoOutlined = Template.bind({});
DemoPrimary.args = {
 onClick: () => {},
 variant: 'outlined',
};


export const DemoText = Template.bind({});
DemoSecondary.args = {
 onClick: () => {},
 variant: 'text',
};

How Do I Write Stories for Complex Components?

While simple components, like buttons, do not need any logic to visualize them with stories, more complex components – for example, a select component – will need both a state and state change logic in order to function correctly in the story. In this case, you will need to expand the template with values, state, and change listeners.

Let’s take this simplified select component as an example.

export interface IMySelectProps {
 label?: string;
 values: { name: string; value: string }[];
 selectedValue: string;
 onChange: (event: SelectChangeEvent<string>) => void;
}


export const MySelect: FC<IMySelectProps> = ({
 label,
 values,
 selectedValue,
 onChange,
}) => {
 return (
   <Select value={selectedValue} label={label} onChange={onChange}>
     {values.map(value => (
       <MenuItem value={value.value} key={value.name}>
         {value.name}
       </MenuItem>
     ))}
   </Select>
 );
};

This component doesn’t function on its own; it requires logic on its parent component in order for the user to see and select options. 

Let’s now create a story for it.

First, create a new file called “MySelect.stories.tsx” next to the Select Component file. Then, like in the button story, create the default export object.

export default {
 title: 'Common/Select',
 component: MySelect,
 argTypes: { onChange: { action: 'onChange callback was called with' } },
 args: {
   label: 'Fruit Select',
   values: [
     { name: 'Banana', value: 'banana' },
     { name: 'Lemon', value: 'lemon' },
     { name: 'Orange', value: 'orange' },
   ],
 },
} as ComponentMeta<typeof MySelect>;

You can add two new fields next to the title and component fields used previously.

argTypes lets you set argument options for your story manually. Here, you can add descriptions for the arguments and, like in this case, add an action to it. The action will automatically trigger in the action section of the canvas, and will output the defined string together with the function’s passed parameters.
In args, you can set default arguments that do not change per story. In this case, add the label and values, so it will be set for all of this component’s stories.

Next up, create the story template.

const Template: ComponentStory<typeof MySelect> = args => {
 const { onChange, values } = args;
 const [value, setValue] = useState('banana');


 const onSelectChange = (event: SelectChangeEvent<string>) => {
   onChange(event);
   setValue(event.target.value);
 };
 return (
   <MySelect selectedValue={value} onChange={onSelectChange} values={values} />
 );
};

First, First, you need onChange and values, which you get from args by destructuring.

Create a state, which will save your current selected value as a string, with a default value. 

In order to trigger the action correctly, you need to call the onChange function of the args. Then you can set the state to the selected value from the component.
Instead of spreading the args, assign the state value, the custom change function, and the values from the default args.

Finally, create a simple demo to show the story in Storybook.

export const Demo = Template.bind({});

The result is a fully functioning select dropdown component you can try out in your Storybook.

Screenshot of the dropdown component in Storybook

What’s Next?

You should now have the tools and knowledge to create your own visual stories for your components – regardless of whether they function without external logic or whether they need additional logic in the parent.

After discussing the process of writing stories with Storybook, read my third and final article. I’ll be showing you how to utilize Storybook’s features of documentation to document your components, as well as give you a brief overview of Chromatic’s visual-regression testing tool.

Manual Tester- (Playtime Supply) (f/m/d) (copy)

  • adjoe
  • Playtime Supply
  • Full-time
adjoe is a leading mobile ad platform developing cutting-edge advertising and monetization solutions that take its app partners’ business to the next level. Part of the applike group ecosystem, adjoe is home to an advanced tech stack, powerful financial backing from Bertelsmann, and a highly motivated workforce to be reckoned with.

Meet Your Team: Playtime Supply

Playtime Supply is building a unique software solution for app and game developers that puts users’ needs first. Instead of traditional monetization mechanisms, Playtime builds an engaging ad experience in which users can play and earn rewards for various new mobile games in Playtime. To predict which mobile game will best suit a user, the team has introduced ML algorithms.

To build this rewarded experience, adjoe’s backend reliably handles more than 200 million users – remaining stable despite impressive growth in the user base. And imagine this: adjoe’s Golang event consumer applications assign rewards equivalent to 700 months’ of time spent in Playtime every day to its users. 

The software depends on two main components.1) adjoe’s Android mobile SDK – written in a combination of Java and Kotlin – which can be bundled by developers in their apps. 2) The team’s highly scalable Golang backend, which is hosted on AWS and is otherwise responsible for developing a modern React (TypeScript) dashboard that provides adjoe’s clients and Business team colleagues with fast-loading insights.
What You Will Do
  • Work in cross-functional teams to achieve the highest level of quality across the software development lifecycle.
  • Collaborate with adjoe’s Product Leads to develop and execute comprehensive test strategies and plans.
  • Conduct manual test cases and analyze results to ensure our SDKs, web apps, dashboards, and APIs are working correctly.
  • Play a key role in reporting and troubleshooting any bugs or errors that may occur.
  • Take ownership of post-release and post-implementation testing.
  • Propose new testing scenarios & work on increasing auto-test coverage
  • Be part of an international English-speaking team dedicated to scaling our adtech platform beyond our hundreds of millions of monthly active users.
  • Who You Are
  • You have 2+ years of experience as a Manual Tester or similar.
  • You are experienced in QA methodology.
  • You are familiar with Agile frameworks and regression/smoke/LIT testing.
  • You are able to document and troubleshoot errors.
  • You have a working knowledge of test management software (e.g. qTest, Cypress, Zephyr) and SQL.
  • You have hands-on experience with Automation Testing Tools (e.g. Appium, Selenium or Playwright).
  • You have excellent communication skills.
  • You pay attention to detail.
  • You have an analytical mind and problem-solving attitude.
  • You have strong organizational skills.
  • Plus: You have experience with (mobile) games QA
  • Have You Heard of Our Perks?
  • Work-Life Package: 2 remote days per week, 30 vacation days, 3 weeks per year of remote work, flexible working hours, dog-friendly kick-ass office in the center of the city.
  • Relocation Package: Visa & legal support, relocation bonus, reimbursement of German Classes costs, and more.
  • Happy Belly Package: Monthly company lunch, tons of free snacks and drinks, free breakfast & fresh delicious pastries every Monday
  • Physical & Mental Health Package: In-house gym with a personal trainer, various classes like Yoga with expert teachers & free of charge access to our EAP (Employee Assistance Program) to support your mental health and well-being
  • Activity Package: Regular team and company events, and hackathons.
  • Education Package: Opportunities to boost your professional development with courses and training directly connected to your career goals 
  • Wealth building: virtual stock options for all our regular employees
  • Skip writing cover letters. Tell us about your most passionate personal project, your desired salary and your earliest possible start date. We are looking forward to your application!

    We welcome applications from people who will contribute to the diversity of our company.

    Build our signature product

    See vacancies