When working on enterprise-grade applications we often have a separate design system and well-defined rules about component usage throughout the entire application. This helps in making components consistent and makes it easy for new developers to contribute to the project without breaking existing design patterns.
Storybook in React allows us to develop React components in isolation, outside the main application. This allows early developers to set rules and patterns which could be used by others as they join development teams. Stories define different states of a component (e.g., a button in different colours, sizes, or disabled states).
This makes it easier to test and refine variations without cluttering our main app or dealing with application-level state.
Consider a CustomButton.js file as shown below:
import React from "react";
import PropTypes from "prop-types";
import "./CustomButton.css";
export const CustomButton = ({ label, variant, disabled, loading, onClick }) => {
return (
<button
className={`button ${variant} ${disabled ? "disabled" : ""}`}
disabled={disabled || loading}
onClick={onClick}
>
{loading ? "Loading..." : label}
</button>
);
};
CustomButton.propTypes = {
label: PropTypes.string.isRequired,
variant: PropTypes.oneOf(["primary", "secondary", "danger"]),
disabled: PropTypes.bool,
loading: PropTypes.bool,
onClick: PropTypes.func,
};
CustomButton.defaultProps = {
variant: "primary",
disabled: false,
loading: false,
onClick: () => {},
};
Stylesheet for the button:
.button {
font-size: 16px;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
}
.button.primary {
background-color: #007bff;
color: white;
}
.button.secondary {
background-color: #6c757d;
color: white;
}
.button.danger {
background-color: #dc3545;
color: white;
}
.button.disabled {
background-color: #ccc;
color: #666;
cursor: not-allowed;
}
Then storybook for above component can be written as shown below:
import React from "react";
import { CustomButton } from "./Button";
export default {
title: "Components/CustomButton",
component: CustomButton,
argTypes: {
onClick: { action: "clicked" },
},
};
const Template = (args) => <CustomButton {...args} />;
export const Default = Template.bind({});
Default.args = {
label: "Default Button",
};
export const Primary = Template.bind({});
Primary.args = {
label: "Primary Button",
variant: "primary",
};
export const Secondary = Template.bind({});
Secondary.args = {
label: "Secondary Button",
variant: "secondary",
};
export const Danger = Template.bind({});
Danger.args = {
label: "Danger Button",
variant: "danger",
};
export const Disabled = Template.bind({});
Disabled.args = {
label: "Disabled Button",
disabled: true,
};
export const Loading = Template.bind({});
Loading.args = {
label: "Loading Button",
loading: true,
};
The storybook will be shown to developers as below:
Well that’s it from my end for today. See you all in the next article.