In this article, we’ll cover how to leverage React and JSX to write components for Storybook for HTML. We also provide reasons for why anyone would ever want to do such a thing. A working knowledge of Storybook and React is assumed.
A bit of background
Before we dive in, let’s provide some context. At DEG, our front-end web development team works on projects of varying size and complexity, including web applications, content-driven marketing sites, headless content management system (CMS) platforms, and landing pages.
Put simply, we want to use the right tools for the job at hand. Or, if you prefer, not everything needs to be a React app.
For traditional HTML websites, our team has used Pattern Lab for years as a component-driven development tool. We build our site elements as Mustache templates, compile and test them locally in Pattern Lab, and then export them to their final destination (often a CMS platform).
Pattern Lab has worked well for us. However, we are not immune to the allurements of Storybook and its ever-growing community.
Our team had recently migrated to Storybook for React to build components for React application, so we were already familiar with its benefits. It wasn’t long before we pondered using Storybook to build components for our traditional HTML websites.
We were initially skeptical of Storybook for HTML. At first glance, one thing that immediately stood out was the repetitive nature of generating a component’s HTML for stories. For example, the code for two stories about a button might look something like this:
As you can see, we have to duplicate the button’s HTML for each story. On a small scale, this is annoying. On a large scale, it is time consuming and not maintainable.
HTML templating engines are a good way to combat code duplication. We eventually came across examples of developers incorporating templating engines such as Handlebars into their component stories. Storybook for HTML was beginning to look like a viable option.
We then had to choose an HTML templating engine. One of our resolutions for 2020 was to move away from Mustache. It has served us well over the years, but we aren’t fans of its syntax and limited logic capabilities.
An idea was taking shape: write React components to generate HTML that we could feed into our Storybook for HTML stories.
With that question answered, we could focus on a proof of concept for our idea. A simple React-templated component to use within Storybook might look like this:
We’ve converted our button example from earlier into a React component. The stories for that button now look like this:
We’re importing our button React component and using it within each of our stories. Hooray, code duplication averted.
So far, so good. Our next step is to prevent Storybook for HTML from choking on our React components.
Storybook for HTML expects each story function to return one of the following:
- HTML string
- HTML DOM element
Our stories are currently returning a React component. To make Storybook for HTML happy, we need a way to convert our React component into HTML.
As it so happens, the “react-dom” package offers a simple method for transforming React components into static HTML: renderToStaticMarkup. This function accepts a React element as a parameter and returns an HTML string. On a side note, a similar technique is used for React-based, server-side rendering frameworks.
Armed with the “renderToStaticMarkup” function, we can create a simple Storybook decorator. Decorations allow us to intercept and modify stories before they are rendered. Ours looks like this:
This decorator accepts a story function, executes it, and passes the returned value (a React component) to the “renderToStaticMarkup” function. The resulting HTML string is returned from the decorator.
Assuming that this decorator lives within a “.storybook/decorators/renderToStaticMarkup.js” file, we can then apply it globally to all stories within Storybook’s “preview.js” file:
Don’t forget to install the “react” and “react-dom” packages into your project.
Odds and ends
And we’re done! Well, almost.
If you try to build Storybook at this point, you will likely encounter compilation errors in your story files. This is because we have JSX syntax in our components and stories, and Storybook for HTML doesn’t understand that syntax out of the box.
This will allow Storybook’s Webpack to understand and compile JSX syntax.
Keep your React components dumb
We are leveraging React components purely as a build-time static HTML generator for our components within Storybook. The HTML for these components will eventually reside within a website that likely will not include React.