Tailwind CSS, with its utility-first approach is known for speeding up the development process. Combining it with the power of React, let’s see how you can build a custom design system for your project to further speed it up, make it scalable and also easy to maintain.
Build a Design System with React and Tailwind CSS
React Summit 2022
Hello everyone, I am Shruti Balasa, a Tech Educator from India. Unfortunately, I could not travel down to meet you all in person, but I am still really thankful to be able to talk to all of you on this huge virtual stage. I am going to be talking about design systems today and how you can build one using react and Tailwind css. Any talk that has the word system in it has to be boring, right? But sorry, I won't make it boring for you. Here's a quick overview of what we'll be covering. Why design system? What a design system is? What is Tailwind css? How Tailwind helps with design system? advanced Tailwind configuration? react components with Tailwind? And finally, some component libraries for inspiration. Whether you already have a design system in place or hearing about this term for the very first time, I can assure you that you will take back something valuable in the next 20 minutes. I always start from the basics. So let's ask the first question. Why design system? You have listened to so many talks since morning and surely design systems have popped up a lot. It's high time you implement a good design system in place. So what exactly is this design system? It's not just some style guide or some component library. Ideally, a design system includes at least these four things. design language, design kit, component library, and documentation. design language is the tiniest set of details that make up the whole of your front end, like your brand colors, the type of fonts you use, including font sizes, font weights, and then spacing between elements, rounded corners, sharp corners, and so on. design kit is the set of assets or graphic files the designer gives you. It can have icons, symbols, templates, mockups, and so on. Component libraries, I'm sure you know what this is. It's a set of reusable components like headers, buttons, form elements, cards, and hundreds of small building blocks. Finally, documentation brings together all these parts with references to each of them and lists the do's and don'ts. For the next 15 minutes or so, we will focus on these two parts of the design system, most important to us as developers. Now enters Tailwind css. Of course, you've heard of it, maybe used it too, and some of you love it. Some of you might even hate it. But for those of you who don't know what Tailwind css does, here's a quick two minutes intro. Tailwind css is a low-level css framework that gives you the building blocks to style your web pages without having to leave your html file. No context switching. Tailwind has hundreds of utility classes like these, text-white, text-center, where text-white will set the color of your text to white and text-center will center it. Then something like this, bg-blue-200 will add a light blue background. Tailwind has about 220 shades by default that you can use. Here's just a sample. Tailwind has 22 main colors with 10 shades each, where 50 suffix is the lightest shade and 900 is the darkest. Next, the h20 that you see here is one of the fixed-height utility classes. There are about 40 such classes, h1, h2, and so on. These are some samples from the documentation, and the documentation is amazing, by the way. You will find anything you're looking for within seconds. Then something like this, h20, w20, both of them about 80 pixels width and height, then rounded-full. So there's no need to use border, radius 50%. You can simply set rounded-full. That's another great utility class. And this is one of the most amazing things in Tailwind. Look at that. By default, it's a square, but after md breakpoint, that is for screens larger than md breakpoint, which is medium breakpoint, you can add a border radius rounded-full. Right? So you can specify any utility class using these breakpoints to change styles and without using any media queries as such. Much lesser code. And here's another thing. Dark mode. It knows these dark variants by default, text gray 800, that is it's a dark gray color, and in dark mode, it's text white. We saw classes for text color, background color, border radius, and heights. The same way, Tailwind has utility classes for almost every single css property with most commonly used values. Using these default utility classes, you can build even the most complex layouts like this one and not have to write a single css rule. You don't have to invent class names and you don't have to constantly switch between html and css files. All right. Now let's get to the crux. So how exactly does Tailwind css help build a design system? For that, let me close my slides and let's look at some real code. This is a react project I've created using create react app. I've installed Tailwind css following the documentation. It's pretty straightforward. I have also removed the default content from app.js and added just a heading here, paragraph, and a link, and just some utility classes here. Now this is what we have in the browser to begin with. Great. Now here is our main file, the Tailwind configuration file, which is generated when you install Tailwind following the steps I just mentioned. This is the default configuration for a react app. If you want to use Tailwind as it is with all the default styles out of the box, you don't need to make any changes to this file. But to build a design system, this is your most important file. Assume you're given a style guide, something like this by your designer. I've taken this from Pinterest. It's just a really simple example. Let's say we have these base colors, red, green, and dark blue, and there are darker shades below. Also, we have black and two gray shades. Now let's add these into our config file. Within theme block, add colors because we don't want to be using the default Tailwind colors. We want to add the ones given to us by our designer. You can either say red or you can say primary, secondary, however you want to name them. I'll simply say red and use that value, which is hash FF357B. And similarly, you can add green with the value given, which is hash 27EFDE. The moment you add these colors, instead of BG blue 100, you can do something like BG red, and that gives you a background red color. Similarly, you can do BG green, you can also do something like text red, border red, and so on. Basically, you can use these colors anywhere you want. But we had two shades of red, right? A darker one and two shades of green as well. To include two shades, you can also do something like say dark red, but that's not what we want. Let's use the object syntax to include that right here. Let's say the default red is this value, and dark red is whatever is the dark value there. Let me just paste it. And then you can do the same thing for green as well. Now let's try and include these in our app.js. H1 class name, let's say text red. See the moment I start typing text hyphen R, you can already see the auto-completion here. This is by the plugin Tailwind css IntelliSense, which is really amazing. The moment you change your configuration values, the auto-completion automatically happens. So now let's say text red and let's see if that works. Yes, so that is working. Now you can continue to add those dark blue, black, and green and so on. Did you notice that now we have only this red and green colors? We don't have the blue 100, 200, and all the other 220 shades in Tailwind. But let's say you want some of those Tailwind colors, you can include them. You need to first import colors like this, require Tailwind css slash colors. And then you can use, let's say you need indigo color. You can say colors.indigo and then you can use, you can say bg indigo 50, 100 and so on. But since we are creating a design system, we wouldn't want to do something like that. We want the colors given to us, but we might surely need white. So let's just add that here. So this is about colors. Next most important set of properties in design system is font styles. Let's customize font family first. Font family and the default font family used by Tailwind is sans. That is, it applies font sans to the whole of html. So anything you change here will automatically get applied. Let's say you want to use the open sans font and then the fallback like this, you can use the array to mention. So now when you say font sans, you will be seeing open sans. Let's say you want to add another font. You can call it heading. And when you say font heading, we would want maybe Playfair display and the fallback being serif. Let's try this out. Let's use this on our H1 by saying font heading. You can already see that here. And yes, we have the serif font. Once again, the default font family sans, whatever was there in Tailwind is gone. This is OK for font family. Now text size, let's say, you know, there are so many text sizes that Tailwind offers, like you can see text XS being extra small, SM, Base, LG, XL and so on up to text 9XL. Let's say you want to keep all of these, but also include another text size, something like text double XS. Now to do that, if we add something like font size, sorry, font size here within theme, the available ones get overridden. Since we don't want that, remove it from theme and instead add it in the extend block. So whatever is available by default still remains and it's extended with these additional values. So let's say you want 0.6 rem. All right. So can you observe what exactly we're doing here right now? We are adding all the design tokens of our design language into the single config file. So this file is essentially our design language that we spoke about initially. Why is this important? Of course we can create components and react, which we will in a minute, but components don't cover a hundred percent of the design. It might cover even up to 70%, but the rest will still have elements with styles that you will have to write. And those can easily become inconsistent with the rest of the page. With Tailwind, you can enforce the colors, font sizes, font weights, border radius, box shadows, padding, margin, breakpoints, and everything you can imagine. So the developer will only use the options available in the config file and maybe add new ones right here and then use them. In my opinion, this is the biggest benefit of using Tailwind css for your design system. I just showed you how to customize colors, font family, and font size. In the similar way, if you would like to customize the entire configuration available in Tailwind, you can refer to the default configuration. To get that file, let me open a new terminal tab and let me do npx tailwind-css-init using the full option. Now let me give it a different name because we already have the tailwind.config.js. Let's call it tailwind-full.config.js because I just want to use this as a reference file. And here we have it. There. Can you see within theme, we have screens, which is essentially your breakpoints. So you can copy this if you'd like to modify, paste it here, and then add an excess breakpoint here, like 480 pixels. I usually do that. Remember that you cannot extend screens and add breakpoints. It'll just mess up. Usually for screens, the breakpoints, it's best to copy everything and edit here. You'll have to add all of the ones you need. You can also add 3XL and so on. And then we have colors we just saw within theme. We have columns, we have spacing. I would like to keep all of this because whenever you do H8 and P11, it adds padding 2.75 rems. If you do W8, it'll add 2 rem. So we might need most of this, and this is anyway not a part of design system. You can additionally add 100, 120, whatever you need. Animation, you can customize this. Aspect ratio, background image, opacity, brightness, and so on and so on and so on. I would ideally retain 75% of the stuff, but change only things like colors, all the typography related classes, box shadows, border radius, opacity, and things like that. So let me close this up. Let's make our heading actually look like a heading by adding text 4XL and font bold. This makes it look like a heading. Now do you notice every time we need a heading, we will want it to be bold maybe. We will need a particular size for H1, maybe text 3XL for H2 and so on. We'll definitely need font heading and we'll need a color as well. Usually this is consistent throughout your website, but adding all these four utility classes every time is too much. Also creating a heading component might be an overkill. In such cases, you have two options. One is you can extract all of these and you can put them in your index.css file within layer base and say H1 and using the apply directive, you can apply all of these and now this works. But this will become a second file. I want everything to be in my config file itself. So let me remove this. Let's not do it like this. Instead, let's add the base styles in the config file itself using plugin for which let's import a plugin, const plugin. And now within the plugin array, let's call the function and pass an anonymous function within which takes an object and we can deconstruct it into multiple helper methods. The helper method we need right now is add base because we want to add the base styles. I'll also need something like theme, which I'll tell you what it is in a moment. Within this, call the add base helper function and then specify the elements that you'd like to style. So for H1, let's add a font family. Here you need to use the css and JS syntax. And here I would want this particular value here, which is specified in the theme. So whenever you want to access a value in theme, you can use this theme function. So theme font family dot sans. So that will give me this value here. Let's also add font size. Sorry, font size. That would be theme font size dot for Excel and also a font weight theme font weight dot bold. And now here, let me add only the color. Yeah, we can add that also in the config file, but I'm just showing you that both can be combined. That is, you get all these styles plus the additional utility classes that you add here. And great. Now any H1 we add in the page will have those three base styles. So once again, we have everything in the config file itself. So awesome. This is about everything with respect to the configuration so that our design language is taken care of. The last thing we're going to do now is create one reusable component with Tailwind. So you get a basic idea for creating your own component library. The second part in the design system that we said we'll talk about. So first for that, let me add some. Sorry, I'll close this also. I'll close this as well. Let me add some styles to this button to this link to make it look like a button. Let's say we need some margin top. We need some inline. We need this to be inline block and then some background BG red on hover. This needs to be BG red dark. Then on focus, this needs to be BG red dark, then some, then the color text white and then padding horizontal padding PX4 vertical padding PY2. Of course, this is a lot. You wouldn't want to add this every time you create a link, which is why we are going to create a button link component. To save time, I've already created this right here. So here's a button link component with href class name and children. We can directly use this here, replace this with button link and yeah, it's imported as well. Sorry. Yeah. Let's check. Of course, we have the same thing right here. Let's also add some rounded corners, maybe rounded MD. Great. We're using this component, but we don't want to specify class names like this right here. So what we will do is if you can observe, there are some general styles here that all the buttons might need, like inline block and rounded MD, but there are some specific utility classes like BG red, hover, focus styles, all of these. This we might want to keep changing, like we need, we might need a green button or dark blue buttons like we saw in the style guide. And then these padding might vary based on the size of the button. So what I'll do right now is create a classes object with some base styles, then some styles related to color and then some classes related to size. And here I will take inline block from here and also rounded MD and add that here. Inline block, rounded MD, then I will add the BG red and all of this into color and then into size I will add these. MD2, I would like to retain it here itself. All right. And now let's combine all of these using the class names npm package. Let me import it first. Import class names from class names. And yeah, here I'd like to use class names. This also gives us the same thing, but we'd like to customize the size and color as attributes. So what we'll do is we'll add them as props here. But before that, let's create options. Red and this would be red. And then similarly, let's have a green button. Similar to that, let's also change the size to give some options like SM. That would be BX2, BY1, maybe a smaller padding and then maybe MD. That would be BX4, BY2, then LG, BX6 and then BY3. And here let's say size and then color. Let's add the default, sorry, yeah, let's give a default of MD size and a default of say green. And here now this would be color and then size because each one is now an object. Okay, this should work by default. We should have a green color and a medium sized button and perfect. We have that. We can customize this now using size equals, let's say LG and then color, sorry, color is red. Perfect. We have a slightly large button with red color. Of course, you can extend this further. This was the most simplest example. You can use prop types. You can use enums and make all of this more robust. This is really just a very basic example. All right, so that's it. Building a design system takes a lot of dedication, but if it's done well, it's easier to use and maintain it as well because a design system keeps growing with new components too. I found some react and Tailwind css open source libraries that I'd like to share here. So, we have a Tailwind, Tailwind, WCAG UI, Windmill react UI, and Kimia UI. These are some good examples. Each of them have implemented in slightly different way. You can take a look and take some ideas from there and build your own design system. Well, that's a wrap. Thank you for listening. I really hope you took back something useful from the session. I'll be happy to answer if you have any questions at all. I'm not a react expert, but Tailwind, yes, I'll do my best to answer. Signing off. Bye-bye. Thank you.