Storybook x React x Typescript | How to manage complex props with simple control
Alexandre Fauchard
Posted on May 1, 2022
The problem
When you're implementing a Storybook you can change your components props with Storybook's controls. But sometimes, when you have a complex props, controls are not adapted and you may need multiple control for one props and/or have to mock some data.
The problem come with Typescript, your argTypes
is waiting for a type equals to the component props type. But I have a good news ! I'm going to give you a trick to properly bypass this problem.
The trick
Let's take a "simple" complex prop as an example :
I have a component Heading
with props which have this type :
type HeadingPropType = {
text : {
text : string
html : ReactNode
raw : string
}
image : {
url : string
alt : string
}
}
As you can see we have two props :
-
text
: a string displayed in multiples format -
image
: an image url with an alt attribute which will not be very useful in a Storybook
With this type of props, Storybook will display controls which ask the user to fill an object but I guess we all agree that a string and an input file are more suitable.
We can display them simply with ArgTypes
but making them work is a bit more complicated.
What you need is a HOC (Higher Order Component) which will return your component but with simplified props.
Something like this :
const componentSimplifier = <T1, T2>(
ComplexComp: React.ComponentType<T2>,
propsConverter: (props: T1) => T2
) => (props: T1) => <ComplexComp {...propsConverter(props)} />
These line define the function componentSimplifier
which takes two Generics Types (T1, the simple one and T2, the component props type) and two arguments :
-
ComplexComp
: Simply the component you want to add in your story -
propsConverter
: A function that will convert simple props into complex ones
For our example we have :
T1 = {
text : string
image : string
}
T2 = HeadingPropType
ComplexComp = Heading //The component we want to display
propsConverter = ({text, image}: T1) => ({
text : {
text : text,
html : <h1>${text}</h1>,
raw : text,
},
image : {
url : image,
alt : "default alt string"
}
})
The final call to this function will be :
const SimpleHeadingPropsType = {
text : string
image : string
}
const propsConverter = ({text, image}: T1) => ({
text : {
text : text,
html : <h1>${text}</h1>,
raw : text,
},
image : {
url : image,
alt : "default alt string"
}
})
const SimplifiedHeading = componentSimplifier<
SimpleHeadingPropsType,
HeadingPropType
>(
Heading,
propsConverter
)
That's it ! Now you can use SimplifiedHeading
in your story with adapted controls !
Posted on May 1, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.