I have a button component that can be of different types eg primary
, secondary
, etc:
export const buttonTypes = [
'primary',
'secondary',
'tertiary',
'positive',
'negative',
]
const Button = ({ text, type }) => {
return(
<button className={type}>{text}</button>
)
}
Button.propTypes = {
text: PropTypes.string,
type: PropTypes.oneOf(buttonTypes),
}
In my Storybook file I'm mapping through the options. This means you can see all the variants on a single page and if another string was added to the buttonTypes
array it would automatically be added to the style guide:
import ButtonComponent, { buttonTypes } from './Button';
const Button = () => {
return(
<div>
{
buttonTypes.map(type=>(
<ButtonComponent key={type} text={type} type={type} />
))
}
</div>
)
}
export default {
title: 'Components',
component: Button,
};
The problem is that this doens't work with with many of the add-ons eg knobs. For knobs to work you need Button
to be the actual component, not a wrapper as I did above.
import ButtonComponent, { buttonTypes } from './Button';
const Button = () => {
return (
<ButtonComponent
type={select('type', buttonTypes, buttonTypes.primary)}
text="Button"
/>
);
};
Is there a way to use knobs and show all the variations on a single page? Ideally without having to create each component manually as this is more work and then won't automatically update if a new string is added to buttonTypes
.
Storybook Addon Knobs allow you to edit props dynamically using the Storybook UI. You can also use Knobs as a dynamic variable inside stories in Storybook. Framework Support. This is what Knobs looks like: Checkout the above Live Storybook or watch this video.
ArgTypes are a first-class feature in Storybook for specifying the behaviour of Args. By specifying the type of an arg, you constrain the values that it can take and provide information about args that are not explicitly set (i.e., not required).
Use the grouping feature of knobs, that way each instance of your component will get its own knob instance instead of all the knob instances being shared between all of the component instances. You can even mix grouped knobs with non-grouped nobs if you want certain things to be shared and other not to be.
In the following example, I have a <Button/>
story where each instance has its own copy of the type
and disabled
properties, but the text
is shared between them all.
Each button type gets its own panel where you can set its type
and disabled
. The "Other" group contains any knobs that didn't have their group set (such as text
).
src/Button/Button.component.jsx
import * as React from "react";
import "./Button.style.css";
export const Button = ({
text,
type,
disabled,
onClick
}) => (
<button
className={`button button--${type} ${disabled ? "button--disabled" : ""}`}
disabled={disabled}
onClick={onClick}
children={text}
/>
);
src/Button/Button.stories.jsx
import * as React from "react";
import {withKnobs, text, boolean, select} from "@storybook/addon-knobs";
import {action} from "@storybook/addon-actions";
import {Button, buttonTypes} from "./";
export default {
title: "Button",
component: Button,
decorators: [withKnobs]
};
export const ButtonStory = () => {
const buttontext = text("Text", "Click Me");
return (
<div>
{buttonTypes.map(buttonType => (
<div key={buttonType}>
<Button
type={select("Type", buttonTypes, buttonType, buttonType)}
disabled={boolean("Disabled", false, buttonType)}
onClick={action(`${buttonType} clicked`)}
text={buttontext}
/>
</div>
))}
</div>
);
};
ButtonStory.story = {
name: "All"
}
src/Button/Button.types.js
export const buttonTypes = [
"primary",
"secondary",
"tertiary"
];
src/Button/Button.style.css
.button {
padding: 0.5em;
font-size: 1.25em;
border-radius: 10px;
border-width: 2px;
border-style: solid;
border-color: black;
}
.button--primary {
background-color: rgb(132, 198, 106);
color: black;
border-color: black;
}
.button--secondary {
background-color: rgb(194, 194, 194);
color: black;
border-color: black;
}
.button--tertiary {
background-color: transparent;
color: inherit;
border-color: transparent;
}
.button--disabled {
background-color: rgb(194, 194, 194);
color: rgb(105, 102, 102);
border-color: rgb(105, 102, 102);
}
src/Button/index.js
export {Button} from "./Button.component";
export {buttonTypes} from "./Button.types";
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With