First up, a confession of sorts. I’m a backend developer. There, I’ve admitted it.
The last time I did any serious frontend work we were using properties on tags, CSS was this mysterious new thing, and layout meant lots (and lots and lots) of nested tables.
Since then I’ve worked on teams with frontend developers, and I’ve been aware of things changing, but I’ve never really needed to do any work in that area. On the few occasions I tried, I learned that things had really moved on, and that CSS was still basically magic to me — but now it was magic with flex and grid and selectors and a whole bunch of other new spells.
Just recently I was playing on a side project, and decided I really ought to see if I could make a UI for it that didn’t look totally terrible. It seemed a good excuse to get a bit more up to speed on frontend matters, and as I had a few days over Christmas, I decided to dive on in.
I knew I wanted a frontend framework that gave a SPA experience for my users, and that having fast visual feedback when I made style changes was going to be key for me. I also knew I didn’t want to use something pre-built like MaterialUI, as having seen that in action before it seemed to opinionated for what I planned to build. So with those requirements, I set out to investigate what kind of stack might give me what I wanted.
Watching a few YouTube videos I decided on a few things:
- React looked like it’d work for me. It seemed to click with my brain, and may be my backend way of decomposing things. Plus Create React App made it super easy to get up and running. Win.
- I liked Storybook as a way to prototype and visualise what I was building. Thanks to my total lack of knowledge it was clear that much experimentation was going to be needed, and having a tool like Storybook would massively reduce the time of the feedback loop.
- Tailwind CSS looked like a winner. I liked the utility-centric nature of it, and I really liked the live streams that Adam Wathan was posting on YouTube showing how to replicate site designs with it. I found this a really easy way of learning all those neat tricks that the FE developers know!
So that gave me the bits I wanted, the next thing was to workout how to get them to all play happily with each other and do what I wanted. It took a lot of fiddling and Googling, but I got there in the end! Here’s what I ended up with, so hopefully if you’re interested in setting something like this up, you can do less Googling, and more React/Tailwind/Storybook hacking.
This article assumes you’re already aware of what React, Tailwind and Storybook are and do. They each have great websites, so I’m not planning on diving deeply into each of them.
Scaffold a new React application
The first thing we’ll need is a React app to work with. The simplest way of setting this up is to use create-react-app, which will scaffold up everything you need. There’s plenty of information out there on CRA, so we won’t get too far into it here, simply run
npx create-react-app tailwind-storybook
This will create a boiler plate app, install all the modules needed to get it running, start a development server to run it, and open a browser tab so you can see it.
Install Tailwind CSS
Now we have our app set up, we can add Tailwind CSS and the tools needed to work with it.
First we’ll install the core of Tailwind CSS itself
yarn add @tailwindcss/postcss7-compat
Once we’ve done this, we can create a Tailwind configuration file named
tailwind.config.js in the root of the project
This is a barebones configuration for Tailwind that’s enough to get us up and running. Now we can update the
index.css file in the
src directory to remove CRA’s boiler plate CSS, and instead import Tailwind’s styling instead.
This will give us access to Tailwind’s utility-first CSS classes to use in our project, but in order for it to function properly we need to install a few extra tools so we can add the additional steps to our projects build.
The last thing we’ll do at this stage is to remove the content from the app, and add something that will show us when Tailwind is doing it’s thing. To do this we can update
Right now if we look in our browser we’d like to see a screen centered blue box and some text. Sadly, we won’t — there are a few more tools we need to set up to make that happen.
Add the CSS build tools
Now we have the core of Tailwind installed, we need to add a few steps to our React apps build process in order to actually make it work.
First we need to install PostCSS and Autoprefxer. PostCSS will post-process the Tailwind CSS, and use the Autoprefixer to add vendor specific pre-fixes where needed. We can add both using Yarn, but we need to be a bit careful with versions, as I’ve not yet found a solution to getting the latest version of PostCSS (8 at the time of writting) to work with Tailwind, so we need to force the install of version 7 instead.
yarn add autoprefixer@9 postcss@7
Now that’s installed we need to configure PostCSS so it knows what we need it to do. We need to do this within the build process that CRA runs, but that’s historically been really hard to do with out ejecting the app, which is something we’d rather avoid if we can.
The answer to this problem is a project called Craco, a really handy tool for configuring CRA projects without having to eject then. As usual, we can use Yarn to add it.
yarn add craco
And then update our
package.json file to use it everywhere it would normally use the CRA scripts.
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "craco eject"
Finally we need to configure Craco, so it knows exactly what it is we want it to do, in this case to run PostCSS and Autoprefixed. We can do that using a simple
craco.config.js file in the root of our project.
Now if we stop our React dev server, and restart it, Craco will kick in and post-process our CSS. If we look in the browser now, we should see that our Tailwind styling has kicked in, and we can see a nicely styled splash screen. Or at least something that proves Tailwind and React are playing together!
The great thing with PostCSS and Craco is that this is just the start, we can use additional plugins to purge unused CSS and minimise our bundle size and more — but that’s something for later.
Now we have Tailwind and React set up, we can look at what we need to get Storybook working in this set up. This obviously starts with adding Storybook to the project, which is as simple as running
npx sb init
After the initialisation has run your project should have a
.storybook directory, which contains the Storybook configuration, and a
/src/stories directory that contains a bunch of example components and stories. We don’t need these examples, but before we delete them we can run up the Storybook development server and check everything’s working. Storybook has added a couple of extra scripts to the
package.json file, so we can issue the following command
npm run storybook
Point your browser at
localhost:6006 and you should see a Storybook containing the example files. If everything looks good, and you don’t want the examples anymore, you can just delete the
Adding a first Tailwind styled component
Let’s add a really basic component to our project, along with a simple story for it. In this case we’ll add a custom button, with a prop to set it to primary or secondary mode. Create a
src/components/Button directory, and then add the four files below to it. You’ll also need to use Yarn to add the classnames package which we use to dynamically adjust classes based on the props.
There’s not much clever going on here at all, a simple React function component, some Tailwind styles, an a couple of stories for Storybook. You can find out all about writing stories on the official site, we won’t get into that here.
The big problem, however, is that if we look at the story in the Storybook UI, we see a plain old browser default button. It’s 1998 all over again, and while retro is pretty cool, it’s obviously not what we were really aiming for!
Making Storybook ❤️ Tailwind
Much like how we had to make our CRA build aware of Tailwind so it could process the styles, we have to do the same for Storybook. It turns out that we have all the bits we need already, we just need to tweak Storybook’s config so it knows what to do.
Within the project’s
.storybook directory theres a file called
main.js, and that’s where we need to head. In here we can update the Webpack config that Storybook uses, so that it performs the same PostCSS actions when building the storybook that Craco allowed us to do when building the app itself. Here’s what we need to do that:
Now when you go look at the stories the plain gray button should be no more, and something a whole lot more (Tailwind) stylish should be there instead.
Better yet, as you start updating you component everything is live mirrored into both the running app, thanks to Craco and the CRA development server, and into Storybook thanks to Webpack and Storybook’s development server.
So, it might have taken a while to get everything playing ball, but now it does, how does it work?
Well, for me, pretty perfectly. React had a relatively gentle learning curve, at least to be able to put something that worked together! It’s got good documentation, and thanks to the number of people using it the community offers a great depth of support when you do hit speed bumps.
I love Tailwind, and what Adam is doing with it. No more un-styled buttons for me!
And Storybook helps me to see the components I’m building so I can rapidly iterate on my ideas — and experiment when I still can’t quite get CSS to do what I want.
If you find this article interesting, and decide to give this stack a go, I’d love to hear about your experiences!
In the second article in this serious, published here, we’ll take this framework for a spin, and demonstrate how it can be used to very quickly create highly effective UI components.