Integrating Storybook and Chromatic to AsyncAPI Website
The AsyncAPI website is built using Next.js v14 and TypeScript. Next.js, a powerful framework that leverages React's capabilities, allows us to create feature-rich web applications. In this blog post, I will delve into setting up Storybook v8, a frontend workshop for building UI components and pages in isolation, and Chromatic, a visual testing & review tool that scans every possible UI state across browsers to catch visual and functional bugs, in the AsyncAPI website. I will also be discussing the challenges I encountered and sharing the valuable lessons I learned.
Installing Storybook
To initialize the storybook into an existing Next.js project, Storybook Documentation suggests to use the following command:
# Add Storybook:
$ npx storybook@latest init
However, I encountered a snag while running this command inside my existing clone of the website repo in my WSL environment. The installation process seemed to stall indefinitely. I attempted various solutions, including switching to a Windows environment and verifying network connectivity, but none proved successful. The issue mysteriously resolved after I performed a fresh clone of the repository. While the cause remains unclear, a clean clone might be the solution if you encounter a similar installation freeze during Storybook setup.
Exploring the boilerplate code
The storybook installation adds the following folders to our project: .storybook
and stories
. The .storybook
folder has the following files:
main.ts
: This is the storybook configuration file and has the following default code:import type { StorybookConfig } from "@storybook/nextjs"; const config: StorybookConfig = { stories: [ "../stories/**/*.mdx", "../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)", ], addons: [ "@storybook/addon-onboarding", "@storybook/addon-links", "@storybook/addon-essentials", "@chromatic-com/storybook", "@storybook/addon-interactions", ], framework: { name: "@storybook/nextjs", options: {}, }, staticDirs: ["..\\public"], }; export default config;
preview.ts
: This configuration file allows users to control how the story renders in the UI and has the following default code:import type { Preview } from "@storybook/react"; const preview: Preview = { parameters: { controls: { matchers: { color: /(background|color)$/i, date: /Date$/i, }, }, }, }; export default preview;
the stories
folder contains sample boilerplate components and stories like Button. Here is the list of files it has:
We won't be needing this boilerplate code so I removed it.
Changing the default story location
By default, Storybook stories are present in the stories
folder. The main.ts
file inside the .storybook
folder has settings to find story files inside the stories
folder:
stories: [
"../stories/**/*.mdx",
"../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)",
],
However, codes that change for the same reasons should be kept together. In that sense, the Storybook file for a given component will very likely change when that component changes — so we will be keeping the Storybook File with its component. Also, if the component folder is moved to another place in the project or even to another project, it will be easier to move the Storybook file along.
So we update the above storybook configuration to look for stories in the components folder:
stories: [
"../components/**/*.stories.mdx",
"../components/**/*.stories.@(js|jsx|mjs|ts|tsx)",
],
Setting up autodocs
and custom documentation template
Storybook Autodocs is a powerful tool that can quickly generate comprehensive documentation for UI components. By leveraging Autodocs, we can transform our stories into living documentation. To enable automatic documentation for all stories, I added it to tags in our .storybook/preview.ts
file:
const preview: Preview = {
// ...rest of preview
//👇 Enables auto-generated documentation for all stories
tags: ['autodocs'],
};
To enhance the documentation structure, I added a custom documentation template to our Storybook. To replace the default documentation template used by Storybook, I extended the UI configuration file (i.e., .storybook/preview.ts
) and introduce a docs
parameter. This parameter accepts a page
function that returns a React component, which we can use to generate the required template.
import { Title, Subtitle, Description, Primary, Controls, Stories } from '@storybook/blocks';
const preview: Preview = {
parameters: {
// ...rest of parameters
docs: {
toc: {
title: 'Table of contents',
},
page: () => (
<>
<Title />
<Subtitle />
<Description />
<Primary />
<Controls />
<Stories />
</>
),
},
},
};
This toc
property of docs
parameter adds a Table of Contents section on the right side of each documentation page.
Changing the font used Storybook
The AsyncAPI Initiative uses Work Sans font overall on its website. So, I decided to update the font used by Storybook. However, this was a tricky part. We can't change the font used by the storybook through its configuration file. After a little research, I found that we can use .storybook/preview-head.html
file to add extra elements to the head
of the preview iframe, for instance, to load static stylesheets, font files, or similar.
When preview-head.html
file is defined in our .storybook
directory, it is then treated as the head element of our Storybook. This gives us a place to import our font from Google Fonts CDN and also define a style tag where we can apply the font to the body element. Here is how my preview-head.html
file looks like this:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Work+Sans:ital,wght@0,100..900;1,100..900&display=swap"
rel="stylesheet">
<style>
body {
font-family: 'Work Sans', sans-serif;
font-optical-sizing: auto;
font-style: normal;
}
</style>
Setting up Chromatic
Chromatic is a visual testing & review tool that scans every possible UI state across browsers to catch visual and functional bugs in our project. It provides a unified workspace for designers, product managers, and other stakeholders to share feedback and sign off on UI. We will be publishing our Storybook using Chromatic as it also allows us to configure CI to run your visual tests whenever you push code and get pull request badges to get notified about the test and review results.
Here is how I installed Chromatic to our project:
$ npx storybook@latest add @chromatic-com/storybook
We need to Sign in to Chromatic to create a new project for our repository. Then we need to grab the CHROMATIC_PROJECT_TOKEN
from the project settings. Now whenever we need to publish our storybook we will need to run the following command:
$ npx chromatic --project-token=<CHROMATIC_PROJECT_TOKEN>
Integrating Chromatic into our CI pipeline
We can configure CI to run visual tests whenever we push code and get pull request badges to get notified about the test and review results. We need to add a chromatic
script to the package.json
to run chromatic:
"scripts": {
"chromatic": "chromatic --exit-zero-on-changes"
}
To automate Chromatic with GitHub Actions, I created a new file called chromatic.yml
in the .github/workflows
directory and added the following:
# .github/workflows/chromatic.yml
name: "Chromatic"
on: push
jobs:
chromatic:
name: Run Chromatic
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
# ⚠️ See your package manager's documentation for the correct command to install dependencies in a CI environment.
run: npm ci
- name: Run Chromatic
uses: chromaui/action@latest
with:
# ⚠️ Make sure to configure a `CHROMATIC_PROJECT_TOKEN` repository secret
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
We need to set the CHROMATIC_PROJECT_TOKEN environment variable (sometimes referred to as “secrets”) in our repository's GitHub actions.
Conclusion
The above setup and configurations set a base to add stories. That's it! Now we are ready to write, share, and review stories visually with Storybook and Chromatic for all components in our AsyncAPI Website. In the next blog, I will be delving into writing our first stories and will discuss the challenges I encountered, and share the valuable lessons I learned. Till then make sure to test your codebase with multiple edge cases before pushing it to the main branch.
Subscribe to my newsletter
Read articles from Ashmit JaiSarita Gupta directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Ashmit JaiSarita Gupta
Ashmit JaiSarita Gupta
I am an engineering physics undergraduate passionate about Quantum Computing, Machine Learning, UI/UX, and Web Development. About two years ago, when I first discovered the field of Web Development and Quantum Computing, it totally amazed me and I have been dedicating my education to them ever since. Over the past two years, I have dedicated a considerable amount of time and effort to learning and developing skills in these fields by taking various online courses, reading different articles, making several projects, and being involved in various research internships and mentorship programs. Fast forward to today, I am currently working on a modern streaming platform and researching QUBO Relaxation Parameter Optimisation using Learning Surrogate Solver (QROSS).