Tru Narla: Building a design system in Next.js with Tailwind

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
foreign [Music] my name is true I go by Mutual on the internet and I'm a software engineer at Discord I'm also kind of a big deal on the internet I've been using nextgs for a while now and it's super exciting to be able to talk at this conference today I'll be telling you a haunting tale about how to implement your own design system in nexjs before we start talking about how to implement a design system we first have to Define what a design system is a design system is a set of reusable UI components and design tokens so like colors and fonts that bridge the gap between designers and Engineers designers use tools like figma or sketch to design UI components that can be reusable across multiple projects and still look cohesive whereas Engineers Implement those components in whatever framework that they choose using various tools so here's an example of a design System created in figma currently there is a couple of ways to implement Design Systems within your project you might be familiar with some existing component libraries such as manteam chakra mui Etc and as good as those UI libraries are they're also very opinionated so if your design team has designs in mind that are very different from what you get out of the box with those existing UI component libraries you'll have to go in and write a lot of code sometimes this is fine but this could get really tedious and annoying if the designs are very unaligned the other option instead of using something pre-built is to build your own design system from scratch this allows you to be as opinionated as you want and easily match the existing design System since you have to build it all yourself however nice this seems implementing your own design system can be overwhelming you have to define a lot of styles figure out accessibility pick how opinionated that you want to be and you have to maintain the system so that you don't have Tech debt thankfully however hard it may seem the Tooling in this area has become much better another thing to keep in mind is you only have to build out the components that you need in your design system a lot of these existing UI component libraries that I mentioned earlier come pre-built with so many different components and you only use like a handful of them most of the time so the scope of building your own design system isn't nearly as as big as building out one of these open source UI component Library so here's a way that I found that might help you implement a design system there's a couple of key technologies that we'll use here and I'll talk through all of them so the first is talent I was actually very anti-tailwind in the beginning and I started using it on stream and I really like the ease of use of using tailwind and also how I don't know it's just so easy to bring into any project and quickly get it up and running the reason Tailwind is really amazing for this specific problem is that it's fully customizable to your theme out of the box Tailwind comes with a set of font sizes color themes and spacing increments this can be useful but when implementing a design system you could have conflicts thankfully Tailwind is fully customizable you can overwrite any of these existing presets so since Tailwind is open source you can actually take a look at their default config and basically this is a stub for all the different things that you can change within your Tailwind config so here you can see the different size screens for responsive design you can also see all the colors you can even change the spacing there's just so much here that you could modify within your own tail and config to make it easier for you to use so if you actually look at the Tailwind config that I have in my project here I'm actually just defining a brand color and so this brand color I can then use as one of the talent colors so instead of saying you know text Gray I can say text brand and it shows the actual brand color that I Define you can also change default colors so here I am changing the default ring color to be the brand color because of this you can truly build anything with Tailwind Tailwind gives us the ability to Define our Styles but how do we make this work within our components components will accept props and we need to conditionally assign classes based on these props that are passed in a common solution to this is to use something like class names or clsx so here is an old button that I had that uses clsx to conditionally apply classes now if you see here the props for this button basically had an intent and that is what I want the button to look like so here there's a primary secondary and a danger button and so in the component button I'm grabbing the props and I'm setting the initial state to intent to primary and now we use clsx here in the class name to basically combine the classes together based on the conditions that are being applied so clsx first takes in default class names so these are just all the tail and classes that are being applied no matter what the prop is that's being passed in and then here you can see that based on whatever the intent is we're changing the background color and the text color of these buttons so you can see that if we only have one prop that's being passed in it's not that bad but this could get really complicated if your button takes in like 10 or 12 props this is where class variance Authority or CVA comes in CVA gives you an easy to use interface to Define variance which conditionally apply sets of classes CVA can also Express default variance and even compound variants where classes can be applied based on a combination of variants as a nice side effect the typescript type for variance is also super easy to incorporate into your component using the variant props type helper we'll take a closer look at this during the demo the other thing to keep in mind when you're building out your design system is to account for accessibility thankfully there's a lot of great Solutions in the space I'll be working with headless UI but there's also things like react Aria and Radix UI which are also great libraries worth looking into when we're developing with our design system we can also use a few techniques to make our life easier with typescript we can set up a path Alias so this lets us import our UI components from a consistent path instead of a relative path I can set up at UI slash to basically point to the folder that our UI components are in so here in my ts config I'm setting a path and I'm setting at UI slash asterisk to point to the source components UI folder so now if we go take a look at our note component over here we can see that when we're importing all these components from our UI folder that the path is now at UI slash and whatever the path name is so it makes it super clean and easy to use if you're using a mono repo this can also help because you can Define your UI components as a shared internal package and so the last tool we're going to bring in is storybook storybook is an isolated component playground where we can test our components outside the context of our application this is critical when building UI component libraries because it lets you avoid having to run the entire app to test all the states of different components that you build for example you could have a delete button that only appears on a specific page and so in storybook what you can do is just render the delete button component and be able to change the props however you please and see how it looks based on the different props and now here's the demo let's get into it all right so here is our project Nitro this is a basic nexjs application so here in my source file I have my components and in my components folder I have my UI so here you can see things like button form input menu Etc so let's take a look at the code specifically for these buttons that you see here so we looked earlier at a way to do this with clsx and passing in different props and then changing the class names based on those props if we take a look at button you can see that here I'm importing in CVA from class variance Authority so here I'm defining button styles by basically calling CVA and then passing in default Styles but the cool thing about CVA is we have these variants so here I have a variant and in there I have this thing called intent and so here when I have the primary secondary in danger intent here's the styles that would get applied based on whichever intent is being passed through not only can you do variants based on the use different words you can also do Boolean variants so here I have a full width variant that's basically saying if this prop is passed in then make the button full width here I'm only passing in true but you could also pass in a class name that would get applied if this was set to false the other cool thing with CVA is you can Define the default variance as I mentioned previously so here what I'm saying is if there's no intent being passed in default the variant to primary so now if we scroll down and we take a look at this component you can see our props extend button or link props which are basic button props and then we have this type variant props which basically take in the type of button Styles you can see here all of our types properly typed so when I go into the button component and I'm actually grabbing props I can actually extract intent and you can see here the type of intent is primary secondary danger and the type of full width is a Boolean so if I do type in an intent you know let's say it's like tertiary this typescript will yell at you because it's not a valid type when you render in whatever component you want for the class name all you'd have to do is pass through the button styles with the intent and full width and any other props so now that we've seen what a button created with CVA and Tailwind could look like let's change up some of the variants and see how it works so here we have the code running and there is a login button a sign up button and a view your notes button that basically are all the same button component but with different props passed in so if we go take a look at these here we have the button and the intent of the login and sign up button is secondary but I can just come in here and change it to primary and you can see that it changes something that I mentioned earlier was accessibility and so here I use headless UI for my accessible components so if you look at our website we have this new note button and there's a drop down and I can access the different things without clicking via the arrow keys so how do we build this drop down using headless UI so if we go back to the code as you can see here we use this new note button and it leverages the menu the menu button and the menu items Etc from headless UI so if we look at the menu implementation here in our UI components folder we basically just leverage headless ui's component the menu component and just add a couple of features on top of that and so this is pretty default implementation I do use clsx here for the button or link this is basically the items in the drop down I haven't really fully fleshed out all these components with CVA yet but this is somewhere where you could add that as well so now if we take a look back at R note page you can see here that we're rendering this menu button and what we can do is just pass in as and then our button so what this does is this actually pulls in that button that we've made that uses CVA and so the really cool thing is this menu button now that you've declared it as this button you can actually grab the intent and set the prop immediately here so currently I think it's set to primary because that's the default so let's do it to secondary and see what happens and if we look back at our website you can see that it's now gray instead of blue so yeah it's very easy to pull in accessible components and use them in your design system and now let's look at one last thing storybook so storybook is pretty easy to implement so if you look here in our UI folder you can see that we have a button.stories.tsx and here's like sort of a description on what this story looks like so you pass in a title you pass in the component and you pass in the ARG types that you want to change and so down here we basically render that button that component that you want to put in your storybook and we pass in the arguments and now here what we basically do is we have different options so we can set a primary we can set a secondary we can set a danger and these just take in our different intents and so let's run storybook so we can do pnpm run storybook and it takes a little bit to run but once it's open you can see that it opens up here so you know how we said UI button so it's under UI under button and then under the button we have different versions we have our primary we have our secondary and we have our danger and the cool part is you can actually just change them here as well but you set like default values so that's what this is doing and you can also set the Boolean for full width so you can set this to true and see what happens set it back to false and see what happens so storybook makes it super easy you don't have to render these buttons in your actual application to see what they would look like with all the different props that you pass in and so we also do menu in this way so here we have the menu button and we can actually see what the drop down looks like without actually going to that page that notes page and using the drop down there and our menu stories look very similar to our button stories so here we basically are setting the title to UI menu which component it is and then we are just rendering the menu passing in those arguments as we did to the button as well hope you like this talk thank you so much for watching and if you're interested in more from me I'm you true on Twitch on YouTube what else on tick tock on Instagram and unfortunately not on Twitter but I'm true narl on Twitter so thank you so much and have a great rest of your next con bye
Info
Channel: Vercel
Views: 128,368
Rating: undefined out of 5
Keywords:
Id: T-Zv73yZ_QI
Channel Id: undefined
Length: 13min 34sec (814 seconds)
Published: Fri Oct 28 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.