Composing components
Composing components.
After building the Badge
and Review
components in the previous lessons, we have the basics necessary for the RestaurantCard
component, let's go through the process of creating it.
Important
We won't be creating the component from scratch, as it would be too much typing effort, and I don't want you to just copy-paste code, so let's just focus on the process.
As we are going through the process, there will be a few files with pre-configured code to show us every step in this lesson. We will temporarily use files located in the progress
folder:RestaurantCard.basic.tsx
and RestaurantCard.unstyled.tsx
. We will be commenting/uncommenting them in the imports of our stories file, then use the final version of the component: RestaurantCard.tsx
. Note that both RestaurantCard.basic.tsx
and RestaurantCard.unstyled.tsx
are there for presentational purposes, and you're free to delete the entire progress
folder if you want to.
If you're not running Storybook, please start it. Now let's get to it.
Defining the scenarios#
The first step is to think about the requisites of the component. Here are the possible scenarios for it:
The restaurant is currently open (default scenario)
The restaurant is new on the platform
The restaurant is currently closed
Loading indicator

We can also prepare some mock data, and based on it, we can define the props for the component.
Here's what RestaurantCard.basic.tsx
looks like, with a minimal template to show these scenarios:
// src/components/RestaurantCard/progress/RestaurantCard.basic.tsx
type RestaurantCardProps = {
id?: string
name: string
rating?: number
specialty: string
photoUrl: string
isClosed?: boolean
categories?: string[]
isLoading?: boolean
isNew?: boolean
className?: string
}
export const RestaurantCard = ({
isClosed = false,
isNew = false,
isLoading = false,
}: RestaurantCardProps) => {
if (isLoading) {
return <div>Loading</div>
}
return (
<div>
{isNew && <div>new</div>}
{isClosed && <div>closed</div>}
Restaurant card
</div>
)
}
In Storybook, every one of these scenarios would become a story. Let's create a RestaurantCard.stories.tsx
file and write the stories in it:
// src/components/RestaurantCard/RestaurantCard.stories.tsx
import { ComponentStory, ComponentMeta } from '@storybook/react'
import { restaurants } from '../../stub/restaurants'
import { RestaurantCard } from './progress/RestaurantCard.basic'
export default {
title: 'Components/RestaurantCard',
component: RestaurantCard,
argTypes: {
rating: {
// we use the same mechanism from review component
control: {
type: 'range',
min: 0,
max: 5,
step: 0.1,
},
},
},
} as ComponentMeta<typeof RestaurantCard>
const Template: ComponentStory<typeof RestaurantCard> = (args) => <RestaurantCard {args} />
export const Default = Template.bind({})
Default.args = {
restaurants[0], // reuse properties from mock data
}
export const New = Template.bind({})
New.args = {
// reuse args from Default story
Default.args,
isNew: true,
}
export const Closed = Template.bind({})
Closed.args = {
Default.args,
isClosed: true,
}
export const Loading = Template.bind({})
Loading.args = {
Default.args,
isLoading: true,
}
Good! This is the playground, and we will see the component evolve as we evolve the code. We can already play with controls to simulate the various scenarios the component handles:
This page is a preview of Storybook for React Apps