Build Your Own UI Library Course | React BaseUI

developedbyed| 04:01:26|Feb 18, 2026
Chapters6
Introduces the course objective to build a own UI library and design system with Tailwind and Base UI focusing on accessibility and a neomorphic aesthetic.

A hands-on guide to building a reusable UI library with Tailwind, Base UI, and a Neo-morphism-inspired design system in React + TypeScript, plus hosting it in a registry for one-click cross-project installs.

Summary

Developedbyed walks you through creating a cohesive UI component library from the ground up. The course blends Tailwind CSS (v4) with Base UI components to ensure accessibility, then demonstrates a Neo-morphism-inspired aesthetic that stays mindful of contrast. You’ll see practical steps for choosing a visual language, building core components (buttons, cards, inputs, switches, sliders, progress bars), and composing them into a design system with tokens for typography, color, and spacing. The series also covers project scaffolding with Vite, integrating Tailwind, and leveraging ShadCN (with Tailwind Merge and CVA tooling) to create robust variants and clean type-safe APIs. At the end, you’ll learn how to host your UI library in a registry (via Chad CN and Cloudflare Workers) for easy cross-project installation, using a registry.json schema and a simple command workflow. Throughout, the focus stays on accessibility, responsive design, dark mode, and practical implementation details, not just theory. By the final episodes you’ll have built a playable demo site showcasing music-player controls, cards, tabs, charts, forms, and a dark-mode toggle, all powered by a single design system.

Key Takeaways

  • Tailwind tokens for color, spacing, and typography drastically reduce context switching and ensure consistent design across components.
  • Base UI provides accessible, unstyled primitives (buttons, inputs, modals) that you can safely compose with Tailwind utilities.
  • CVAs (class variance authority) and tailwind-merge resolve complex variant conflicts, enabling rich component APIs with strong TypeScript typing.
  • Chad CN (Shadcn) registry workflow lets you package components, publish to a registry, and consume them in new projects with a single command.
  • Dark mode and accessibility considerations (contrast, focus rings, aria-labels) are integrated early in the component design process.
  • A practical set of components (Button, Card, Switch, Checkbox, Input, Slider, Progress, Tabs, Badge, Nav) serves as a blueprint for building real apps.
  • Routing of UI through a render prop pattern enables flexible styling of underlying HTML elements (e.g., turning a div into a button or anchor with consistent styling).

Who Is This For?

Essential viewing for React developers who want a scalable, design-system-first approach. If you’re building UI libraries or large front-end apps and want a practical template that combines Tailwind, Base UI, and a modular registry workflow, this course is for you.

Notable Quotes

""We will create our UI library with neomorphism. This is something that became popular a couple of years ago but kind of died out...""
Setting up the design direction and justifying the Neo-morphism choice.
""Tailwind gives you these little utility classes that stop you from worrying about context switching.""
Explains the core benefit of using Tailwind in the design system.
""Base UI essentially just gives you unstyled components that are accessible ready.""
Describes why Base UI is used in the project.
""You can copy over a chunk of your HTML, paste it somewhere else, and it has the styling already attached to it.""
Demonstrates the portability of components with Tailwind.
""Hosting your UI library in a registry lets you one-click install across multiple projects.""
Covers the registry hosting concept with Chad CN and Cloudflare Workers.

Questions This Video Answers

  • How do I set up a design system with Tailwind and Base UI in React?
  • What is CVA (class variance authority) and how does it help with component variants?
  • How can I host a UI component registry for cross-project installation?
  • What are best practices for building accessible Neo-morphism UI components?
  • How do I implement dark mode and color tokens in a Tailwind-based design system?
Tailwind CSS v4Base UIShadCN/ChadCNTailwind MergeCVAs (class variance authority)React + TypeScriptDesign SystemsNeo-morphismTokens (typography, color, spacing)Dark mode accessibility
Full Transcript
Hey there and welcome to the build your own UI library course. In this course, I will essentially teach you how to make your own design system using Tailwind and base UI for accessibility. We will create these gorgeous components that are inspired by Neomorphism. So we'll do our spin on it and at the end of this course I will also teach you how you can host it in your own registry similar to how SAT CN does it. So you can oneclick install it across multiple different projects. So hope you're excited and let's get into it. Before we create our UI library, we have to pick a certain style that we want to apply to all the different components. And the best way to do this is to essentially look back in the past and see kind of what worked and what didn't work. So, I'll take you back to the past. Let's go back to the '9s where skuomorphism became really popular. Now, do know that this time was around where the internet started getting popular. So, a lot of people weren't really accustomed to digital interfaces. So what ended up happening is uh a lot of the UI that was created was trying to mimic real life as much as possible just so that transition to the digital world would become really easy. So for example this video recording app as you can see is actually a 3D rendered microphone here and the buttons as well as you can see they have like shades of shadows and highlights to make them look a bit more realistic. Same for the bookstand here. As you can see, you actually have stands for all the books and you have shadows and a lot of texture as well in the background. So, you're going to see that wooden texture. Same for the note takingaking app here. You have that paper texture with the lines. Whereas nowadays, you probably just see a white background with black text on top. So, it has a lot of character. It has a lot of texture and shadows. Um, and that was kind of the strength of it. So, it was the strength was it was great to onboard new users to digital interfaces. The weakness, it can feel clustered, outdated, and visually heavy. Not only that, I'd probably like to add that shipping and creating these UI interfaces would also take considerably longer uh than some something like flat UI that we're going to have a look at in just a second. But imagine having to create something like this rather than just like a simple recording button, right? You'd have to learn a 3D software like Blender and it would take you a couple of days to actually create it. Not only that, it would actually be more heavy on your website or your application because this would probably take 200 or 300 kilobytes of space. This it's actually like a big rendered uh raster image, a PNG, right? Rather than maybe like an SVG. So those are some things to keep in mind, but these days again it can feel a bit outdated. So, we start moving away from this to something that you probably heard and is still relevant these days. This flat design. We took those complicated shadows and highlights and essentially flattened it to a simple shape here, right? That's 2D. It doesn't have that 3D depth to it. And we just have simple SVG shapes. So, as you can see, the male icon here doesn't have any shadows. It's mainly just one gradient from bottom to top. And if you compare it to skuomorphism here, as you can see, super simple. So the idea is that these days people have become accustomed to like what these things do like what the buttons do on the website. We could look at this trash icon now and say, "Okay, that probably deletes something. This is probably toggling something on and off, you So we got accustomed to it essentially and the strength of this is that it's really simple, clean, fast to render and it scales well. So having these simple SVGs again this is like a PNG here. So take up like 80 to 100 kilobytes whereas rendering out an SVG like this is probably not even a kilobyte. and also implementing a page that's using flat design would probably take you 10 times less uh than doing something in skuomorphism. So the speed of being able to ship stuff has consider cons considerably increased. Now the weaknesses is that it can sometimes feel minimal, lack depth and harder to show hierarchy. So again you've probably seen this a lot of websites do end up kind of looking the same and there's not much character to them anymore. So that's kind of the downsides. It's quite hard to get something a bit more unique. And what are we going to do? We are going to create our UI library with neomorphism. Now this is something that became popular a couple of years ago but kind of died out because there wasn't really a proper set of guides on how to implement it. It was kind of loosely thrown out there and then no one really took it on board. A lot of people said that there are some like accessibility issues and that was more regarding uh to the contrast and what I mean by that is let's let's kind of have a look what is neomorphism anyway again it takes the blend of flat design and skuomorphism combines them together and tries to modernize it. So, as you can see, we have this shape here, and that's kind of pushed out, giving it this like 3D effect using shadows here at the bottom and highlights here at the top. So, we have a nice ring of highlights. So, here at the with the buttons as well, as you can see, they're kind of getting pushed out of the UI, giving that 3D effect. And then you can sprinkle in some textures as well. So, as you can see, this little up button here has a bit of texture. We have those little dots there. And the switch icon here also has these ridges and also shadows and highlights giving it a very realistic look. So, I really really like the style, but again, I haven't really seen a nice implementation. So, I'm more than excited to show you what we're going to make. Uh, and here is another example here. And just for you to know like what other styles are out there, you probably know about this liquid glass one that Apple just made really popular with the new iPhones. Uh unfortunately, this is kind of proprietary to Apple now. So, you cannot really recreate this in the browser. Trust me, I tried. There's no support for making something like this. H but it's really cool. I really like the effect. Another one that was quite popular for some time is called Neo Brutalism. This uses like very harsh borders, like black borders, really thick borders here on the buttons as well, and kind of tries to replicate that 90s retro style. But let's see how we're going to implement our new morphism. So, this is what we're going to create here. As you can see, these beautiful styled components and to fix that accessibility problem that I saw people have is we're going to use a border as well to give that clear separation. And as you can see, it kind of also works together with the shadows and highlights. I'm not sure why people didn't do it this way, but I think it looks really, really nice. So, we're going to create this music player component here. These sliders as well. As you can see, the buttons look like they're getting nicely pushed in as well and pushed out. I just think that looks really, really cool. We have a graph here. I'm going to show you how we can render that out. We have these switches as well that can have the 3D effect. And we have a subscription kind of toggle here. We have a checkbox as well that kind of sticks out there. We have the move goal here. We also have a dashboard. Well, I'll show I'll show you how you can do these tabs. And as you can see, those look like they're getting pushed in. So, really cool. We also render out some badges here. We have a create an account here. I'll show you how you can work with uh inputs as well, accessible inputs. And we also have a smartome. And as you can see, we can also increase the temperature there, which is going to change the color. So, we can toggle between these as well. And this is all supported with light mode as well. And it still looks fantastic. So, there we go. This is what we're going to create. I hope you are excited. I love this one. Uh I'm I I'm so excited to use it in my future projects as well. So, I'm going to pop in with the camera and pop out where it's important so I don't take away too much from the code. Before we get deeper into it, I do want to talk a little bit about Tailwind and base UI. So, I'll see you in the next episode. In this episode, I quickly want to touch on design systems because what we are creating is a UI component library and something like chat is also a UI component library. However, these do not really dictate the language of uh of your website kind of how the feel and the style looks like. That's what a design system is. It uses these tokens essentially where you kind of predefine your fonts, your colors, your font families, and kind of the spacing as well. So, creating a design system on its own is quite it's quite involved, right? For typography, for example, you you're going to have to kind of pick out your own font family, kind of go through all the different headings, subheadings, paragraphs, buttons, and pick out certain sizes for each because if you do random values, the website is just going to start falling apart really quickly and things are going to start looking weird and just not professional at all. Same for the font weight and also like the contrast uh between them is very important. So that's like one aspect of the design system is typography. Uh but you also have colors, right? You might have a primary color, also the background and foreground. How is that going to look like? But you might also have certain colors that you're going to reuse across your website for maybe error messages, right? You might want to have a shade of red for that. Or you might have a success button, right? You might want to have a shade of green. So these are all really important. As you can see, here's a little example here of all the different buttons using this design system and for the badges as well. As you can see, they have certain predefined colors, sizes, uh, and font weights to them. Now, you could when you probably start web development, you probably did this. I'll just show you a little example here. So, I just have a little text here. As you can see, I have a paragraph and a button. We all probably start web development something like this. We define a HTML file. Uh you don't have to follow along for this. This is just like a quick example. Uh and then you have a CSS file here, right? And then you probably did something like this where you grab the button and then you style up this button. So you do a background color for example on it. Let's do I'm going to do an ugly one here, but let's do a light blue. There we go. And there's the color. And then you might add a padding to it. So, I'll do one ram, two ram. There we go. I'll do a dark blue here. If there even is a dark blue, there is a dark blue, but that contrast is not so good. So, let's stick to this. And then you might add a border radius. I'll do one ram. Anyway, you get the point. You just kind of start styling up all your stuff like this. And then you grab the H1. You might want a font size of two RAM on this etc etc. But then you run into the problem where you you start adding multiple stuff right you might go here you might create another div and I have a button here as well that this is maybe like a cancel button and oh crap well that looks the same as that one and I don't really want that. So what do you end up doing? You might start thinking, okay, well, I can just make a class name, right? Create a class name for each. So, you might go up here and you might say this is a class name of button uh primary or something like that, right? And then you go here, you add a class name and then you say button of danger or something like that, right? Okay, cool. So, now we did that. Now we are going to head back to the CSS file and rather than naming it like this you can say okay well my button primary can just have the class of button primary. There we go. And that way I might have picked a different name. Let me just quickly go have a check. There we go. Let's shorten this button primary like that. Okay cool. So now it only applies to this specific button. Uh but the only difference really want I want on the cancel or danger however we named it is the background color. So background I want this to be red, right? But then I still want the padding and everything else to be there. So then you might just go over here and start copying these values and this can start getting quite out of control. Now now we have a different problem, right? We are like duplicating a lot of this code and this is going to get out of hand really quickly. So then you start like introducing maybe another class name into this. So what you end up doing is going here and then you're like well let's kind of just separate these. We'll have a generic button but then we also have a button primary like that. So now we can apply two different class names. So btn and btn danger. So there we go. Let's save that. And now what we can do is head back. And now what we can do is just do a generic btn where we apply the border radius and then the padding. But there we go. But just so you know, like there we go. Save. So it still works the same way, but it's a bit more clear. But we already introduced so many different names and class names that we have to remember just for a button with one simple variant. Now imagine you have 10 different variants for this button. Heck, imagine you have 20 different components with 20 different variants. This is going to get out of control really quickly. you introduce hundreds and hundreds of different class names and that you have to also name, right? And that becomes really really difficult. Not only you have to name all of these different things, you are you are also context switching a lot. You are going between the CSS file and you are going between the HTML file before you can actually get anything done, right? And then god forbid you might have a class name you don't remember. Then you have to go here and just scour your whole CSS file to find that thing. Now this still doesn't solve the problem of what we did here. There's another big problem. We pick random values, right? We pick padding one rem. Okay. Well, we picked a font size of two rim here for the H1. What if this gets becomes a really really big project and you just picked all these random arbitrary values? you're not going to remember those and you are probably going to end up in a situation where you are using different font sizes without necessarily realizing or maybe it just might be really close to it but not exactly and it just starts looking really really weird. So you might think okay well that's a good solution that we can do because we have variables now. So you might go here to the top and create a variable. So you might add it to the body tag or the HTML tag. Actually, it's better to define it on the root. Uh, and let's create it. We are going to create a variable. Let's call this color uh let let's do size actually size LG for example like that. And then you do two RAM here. Okay. And then you do the same for the colors. You do the same for the spacing. Again, you have to kind of name these things, but that's fine. But now, at least now, you can go here and remove this and use a variable instead. So, you can do variable size LG like that and hit save. And as you can see, we have the same effect. Okay. So, there's a lot that you need to do here. You need to pick out the colors. You need to pick out the different sizes. You also need to pick out the different spacings that you have. And you might also have things that you kind of forgot like break points because you might want to have the website look a certain way when it's on small screen or medium screen or large screen, right? So there's a lot of these things that you have to keep in consideration. So this is what essentially Tailwind solves for you. Tailwind gives you these little utility classes uh that kind of stops you having to worry about context switching. So you just do flex flex skull for the colors as well. You have predefined colors. You also have [snorts] predefined sizes for your typography that you can just simply reuse. And this is great because the system that they use is really popular when you learn a design. Uh you essentially want to have a like 0.25 ram incrementation. So that's four pixels and four pixels. So that's how they do their sizing. Uh if we go over here to the docs, let me quickly show you for example for the colors. And they pretty much give you all the colors that you're ever going to need on a website. I never felt the need to reach out for something different. Uh this is a fantastic palette. And then you have all the shades as well. See, like normally you'd have to pick these shades out yourself because you also have to keep in mind, hey, your website may want to have light mode and dark mode. Well, then you'd also need two shades of your main color. So for emerald, for example, you just do color emerald 300 or 700 or 900 and you are done. They give you dark mode as well. They give you responsive design and then you can use these break points. So you can just do MD or LG here and then your site automatically um is going to switch to that and it's very very effective. There's no context switching. You don't have to go between CSS and and index HTML. You can just simply do it in the markup. Another advantage of this is that you can simply copy over a chunk of your HTML, paste it somewhere else, and it just works, and it has the styling already attached to it because you're not linking. You're not doing this weird linking uh with the class names and everything. So, it's really, really powerful. I've been using it for years and I highly, highly recommend it. So, this is what we're going to be using. Uh the other thing that I quickly want to touch on is base UI. This essentially just gives you unstyled components that are accessible ready. Okay? So you don't have to worry about implementing area labels. You don't have to worry about implementing so your components work when you're tabbing over and have good functionality like that. For example, here right for the popup I can press space to enable it. It all of that functionality is already hooked up for you. and you have all the important components that you would need from cordians to avatars, buttons, fields, inputs, and everything else. So that's why we were using that. You might have heard of something like Radex UI. That's unfortunately not maintained anymore as far as I know. That's what chaten uses. So if you're starting a new project, I recommend you actually starting on this one. Okay. Well, let's get ready. Let's start building this out. Welcome to chapter 2. In this one, we're going to start setting up our project and creating our core components for our UI library. So, just so I can give you a bit more space, I'm going to remove myself from the camera here. I'm right behind the browser, don't worry. Okay, so we are going to be using V here as kind of our build tool. This is a fantastic way to get started really quickly. I highly recommend you using this. You can set up a React project, vanilla, vanilla ts project, uh or all of these different frameworks here that they provide. But we are going to stick with react uh which is react ts. Now to install it, there's this command here, mpm create v at latest. All you need is to have node installed. So you can check node v, I believe. And there we go. I have 24. If you don't have it installed, again, you can head over to NodeJS and just follow the installation guideline. It's pretty straightforward. There's not much to it. Okay, so let's run the command create vit at latest. There we go. We're going to say yes here. This is version 8. And let's call this neomorphism 2.0. There we go. We are going to select React for our project and TypeScript as well. Use roll down here. I'm going to say no. This just came out I think a couple of days ago. Don't worry about it. We don't need it. Uh and then we are going to say yes here to mpm install and start and we are good to go. And there we go. That already started up here on localhost 5173. So if we go here to the browser and run this. And there we go. Look at that. We have our project up and running. Now just to kind of guide you through everything that we have, I'll quickly kill the server here. I'll clear it out. Let's just open up so we can see our file system. Let me actually mpm and uh go over in the folder. So cd and I called it new morphism 2.0. There we go. So we're in it. I'm going to use mim. You can use VS Code or whatever other tool you'd like. Uh just to quickly take you through the file system here. We have a node modules. So every package that you're going to install is going to live in here. We have a public. We have a source. The assets here you can put your images and whatnot. We have an app CSS. Now we are going to just simply let's actually clear everything out here. So just delete everything. Hit save. Actually let's just get rid of it entirely. Just delete it. Index CSS here. Let's also clear this out. We are going to keep this file though. And then we have an app tsx which is just going to render out what we have here. However, uh we can remove a lot of this. So let me just start the server back up. Uh let's see where we are. There we go. Let's see the antomorphism I'm going to run npm rundev. Okay, so we're back up. Let's refresh this. As you can see, we got an error now because we don't have the app CSS anymore. So, let's delete that. We can get rid of this logo as well. We can get rid of the V vit logo as well. And the state here we don't need. And then everything pretty much that's in this div, we can clear out. So, clear that out. Clear that out. And let's just rename this to main like that. And for now, we can just add a simple H1 that says hello there. All right. So, just to simplify everything, even this, we don't need the use state. Perfect. The main tsx here essentially just renders out this application. And that's that's pretty much all there is to it. Finally, we have a package JSON, which is important. This is where we we're going to install all of our uh different dependencies. So, let's do that. So, we are ready to go. Okay. So, what we're going to need here, go over to the terminal. We'll kill the application. Let's clear this. I'm going to run mpm I. We're going to do tailwind CSS. Okay, that's installed. We're going to do mpmi. We're going to use um let's see here, lucid react. So, this is going to be used for our icons. And finally, let's also install base UI. So, base UI components slashreact. And we actually also need another package here that kind of bridges the gap between Tailwind and Vit. And that's called Tailwind CSS/V. Okay, there we go. And then any other package that we need, we can just jump back here to the terminal really quickly and add those. But that should be all ready to go now. So I'll see you in the next episode where we are going to start creating our first component. Probably the most important component that we're going to have is going to be our button. So I'm going to head over here to the source tab and I'm going to create a components folder. You're going to see this quite uh frequently and I'm going to do a button tsx. So there we go. Let's open this up. And for now, I'll just export default button like that. And I'll just return a simple button. Here we go. Let's close up the the tags. And let's do a submit here. There we go. Super simple. Nothing too crazy, right? Okay. I forgot to add the function name here. Expert default function. There we go. That should get rid of those error messages. And here it says we have a proper. Don't worry about that for now. We'll just leave it like that. Okay. So to render this out, let's head back to the app tsx. And right here, we can go below this. We should be able to import our button component. There we go. And let's render that out and see if it works. And looks like we don't have the development server running. So let's run that back. Okay. And there we go. We got the little submit button. Cool. Now, it would be nice if I could just pass down any text that I want here rather than just defining it like that. So, what we can do is extract uh the children essentially from the props. You can either do props like this and then extract it like this. Or you can directly do it here like this. Okay. Both of those are fine. Let's just do it like this for now. There we go. So, what we can do here is rather than saying that, we can say children and hit save. And as you can see, we are not getting anything right now. So, I should be able to go back to the app DSX. And rather than doing that, I should be able to simply do a button and then say submit here like that. And look at that. we get the same effect. So now we can style this up however we want. I can go here and change this to cancel. And that works just fine. Now, as you can see, by default, these buttons already have some stylings to them. And each browser is going to have a different one. Uh but they're not too nice looking. So what Tailwind also gives you is something called pre-flight which essentially resets a bunch of the stylings that are already existing between different browsers. So the header here as you can see that has like a certain amount of spacing as well on it. Just make this a little bit bigger here. As you can see it has a big margin on it. The buttons have like these weird borders and like that ugly gray background color. I absolutely hate it. It just looks so ugly. Uh but that's the standard, right? There's nothing you can do about it for now. If I try to do something like this class name flex, as you can see, that doesn't work yet. So, we need to make Tailwind work. So, let's head to the index CSS. And it's really simple to get Tailwind working with Vit. All you have to do is say at import tailwind CSS. Let's hit save. And as you can see, that removes a bunch of those tiles already. However, we also have to do this little configuration here in our Vit config. So, let's go here to the V config really quickly. Go here to the bottom and here in the plugins. Actually, let's kind of open this up. Add a comma here. Oops. Oh, that's annoying. That kind of blocks my whole screen there. But we need to import tailwind CSS from Vit. So there we go. Let's import that. And that should be it. So let's hit save. And we are done. Okay. So cool. It removed a bunch of the stylings. Now I should be able to actually go back to my index here. So let's head over to the app dsx and I'll just wrap these two buttons in a div. There we go. So if I want to add spacing in between them, for example, I can do space X2. And look at that. The spacing gets applied. So that works perfectly fine. Awesome. Now, how can we actually set up our like tokens for our colors and whatever else we want to do? We'll head over to the style CSS. There we go. index CSS I should say and we can use this new team directive. So this works now in Tailwind V4 and I can apply my colors here. So you can create your variables with color. Let's do one for background for example. And the cool part is you can just use all the different tailwind colors. So I can do color zinc 200 for example. I can also do color foreground. So that would be like my text. So, I'll do a darker darker color here. So, color zinc 700. There we go. Let's hit save. Um, and maybe let's also add a primary. So, color primary. I'll pick indigo here. I think that looks pretty cool. And let's do 600 on this. There we go. So, this is how you can define all the different colors for your team. Now you might also have a dark theme that you want to do. So what we can do is essentially create another layer for that layer theme. And I can say here dark. So if we're on dark mode and we can essentially just copy these over and have it applied. There we go. And what we need to do here is is essentially switch these up. So my foreground now will be light. So let's do 100. My background will be dark. So 900. And we can also adjust the primary to get a better effect. But we will kind of modify these as we go along once we have dark and light mode implemented. But there we go. That's how you can define it. So now I should be able to head back uh into my app tsx and I should be able to apply that right here. So I can say class name and if I do a text primary and hit save, this might still not work. Now you might be wondering why. It's because we are not passing the class name prop from here down into this button down here. We are extracting the children, but we're not passing anything else down. So you could do it like this where you extract the class name. However, there's other props I also want to apply to the button like maybe submit or um pretty much everything else that you're going to see here. If you hit control space, these are all the different props and that are already present on the button that you want to make sure you have. And you may want to do area label, right? So you can just spread all the rest out up here at the top with other props like that. Give it any name you want. I'll pick that. And then we can just apply it here. So I can say dot dot dot other props. Let's hit save. And now you're going to see that that button actually turned blue. Okay, cool. However, we want to actually use base UI to create this uh rather than kind of manually adding all all of the different props that we might need. So, in the next episode, we will finish up creating this button, make it look all nice having that new morphism style. But just quickly wanted to show you how you can mess around with uh Tailwind and the layering system here. Uh also I should note that Tailwind works in these layers. So you have layer team. Uh but there's other layers for example the base layer. So if you want to add any styles that are like generally applied to the website, you can use the base layer. Like that's the top level. And then you have an underlying layer. That's the component layer. So if you want something specific for a component and then you have the utility layer. So it kind of takes priority like that. It goes uh base, it goes components and then it goes utilities. All right. So this will have priority over this and this will have priority over this. Okay. So if you add a specific style, uh this will apply before this will apply. Okay. But just to keep it simple, we we're not really going to need much other than the team here and maybe the base layer. So you can call this layer base. And for now, let's just add the background colors that we defined up here. So I want to select the HTML on the body. There we go. And I can do normal CSS here, but if I want to apply using like tailwind stuff, I can use this apply directive like this. Apply. And then I can do bg background. So just normal Tailwind code and text foreground. Set save. And did you see that the background became slightly darker? And we can also test this if it worked by just going up here, grabbing the background color, and just darkening this up a little bit. 500. See, it works. Awesome. So, just wanted to give you a quick intro to how the layering system works here in Tailwind and kind of having the base button setup. Okay, I'll see you in the next episode. Okay, we are ready to start creating our button. So, let's head over to our button tsx and let's see how we can use the base UI button rather than the native button that we are given here in HTML. So, let's head over here to the return statement. Let's just remove this for now. I'll keep props in there, but let's just get rid of it. Let's get rid of everything in here essentially and start all fresh. Okay, so here's how we can do it. We define an element variable and then we can import the use render functionality here from base UI. And as you can see, it says this renders a base UI element. So anything that you want to render you can do it through this use render uh little method that they give you. So this takes in an object and if we expand it we have a default tag name here. And here you are pretty much given all the elements that you might need in HTML. But for now we need the button, right? So let's do button. There we go. It gives us the button. We can add a comma here. Now, we need something else called a render for now. Let's just add it. I'll we'll talk about it in just a sec. And then the props, right, that we're going to need to pass. So, we can add it like that because we're already passing it down like that. And if the names are the same, then you don't need to do say props props to pass it down. You can just simply say props like that. If this if you're renaming this to something else uh different name for props then you'd have to go here and say different name for props right but since the name is the same we can just keep it simply like that and that's it and then here at the bottom we can simply return that element and let's hit save. Now, this is not going to work yet as you can see because this render is not defined for now. Let's just go here and basically pull out the render prop from the props like that. Let's hit save. And as you can see, we have our buttons back. So now everything still works the same way, which is great, but we're using base UI to render that. Now, how do we create variants? because it would be nice if I could simply head here to the app tsx and for this maybe cancel button here I have a variant that I could set to this is a destructive type button like that right there's no real good way for us to do that so here is where I'm going to introduce a new package that's called class variance authority so if you want to have a look at that mpm class variance authority. Oops, there we go. This is the one. Uh, here is the website. It essentially gives us CSS and TS. And I'll show you what that means in just a second. So, let's quickly copy over go to installation here and we can run mpmi So, let's install that. Let's run back the server. MPM rundev. Make this smaller again. Okay, so now check this out. This is what this allows us to do. I can head over here to the top. We'll wait for this little pop-up to disappear. Get out of my way. Thank you. We will define a button variance variable. We can import that CVA from class variance authority. And now here we can define any like base styles that we want. So the button might be inline flex. The reason why I'm adding inline flex is you might want to have an icon rendered inside the button. So you'd want it to go to the like horizontally rather than underneath it. Uh so let's also center that. We can do justify center item center. But more importantly, what this gives us is the ability to add a comma here and an object. So I do curly brackets and I can define my variance here. So I'll do variance and I'll do variant. And then I can do as many as I want. I can have a default one here, I can have a primary one here. Let's do maybe two more. a destructive and maybe a warning one like that. Okay, so you can define your own variants. Now, not only that, you can also define maybe certain sizes that you want to have on these buttons. So, I can go here and say size. I can have a default. So, I can do a height of 12 with a padding of X of four. However, I can also have maybe a small icon or maybe uh sorry, a small size maybe for like icons. So, I can do maybe H 12 and a width 12. So, a fixed size on these things. There we go. Now, one more thing that we need to add here is if we go to the bottom, we need to also say which one of these are the default ones that it should apply. So, you can do that with default variants. Okay? Okay. And that you need to add here at the bottom. So here if you hit control space it should pop up with these two properties. So default variants and basically I'm going to say for the variant I'm going to do default because that's how we named it. And then for the size I'm also going to do default. But again you can pick any you want here. So I can go here. I can do the icon as my default to apply. Okay. But let's go back. Let's do default. Cool. Okay. So, we have this set up now. Now, it's really nice because we can simply go down here and apply it. Now, how would we apply it to this? Oh, sorry. Also, this should have not been here. Let me cut it. It should be in the button instead. So, let's cut this out from here and paste it inside the button. There we go. Add it to the button. We'll go up here. Let's import the CVA here. Cool. Okay. So, this would work if I go here, but I need to kind of add it to the props that's here, right? So, it's quite strange. So, base UI gives us something called a merged props. It allows you to essentially do changes to the things you want to change and then kind of merge it all together and then add it to the element down here below. So we can do con merged props set that equal to. We can import this little utility that they give us. As you can see it says merges multiple sets of React props. It follows the object assign pattern where the rightmost object fields overwrite. So everything on the right will get overridden by whatever is on the left. So merge props. There we go. So essentially what I'm going to do here is we have the render prop. Let's see how we're going to do this. Yeah, let's get the render and then we are going to name this other props like that. Okay. So here I'm going to pass in other props. However, then I'm not going to get render actually out of this. So let's just get rid of this entirely and instead just pass down props here. And this is going to break the render thing here. Uh but don't worry about it for now. We'll get back to that anyway. So here for now, let's just do props dot render. Okay, that should fix it. But again, I want to talk a bit more about what this does anyway. So let's just do that. This way at least we're passing all the props down because how we had it set up is uh the render would not get passed down because we'd extract it separately. So you want to pass down all the props in here and then everything anything that you want to override you can do it in this object here. So what do I want to do? just a class name, right? That's what we want to override. So, class name here. And I can just simply pass in the button variance that I have. There we go. And that's pretty much it. Let's hit save. And then here we can do merged props. Let's hit save. And look at that. All those different stylings get applied straight away. As you can see, there's more padding and everything. So, clearly worked. If I head over here and let's do a maybe a different background. BG red of 200 just as an example. Look at that. It gets applied. Now, one more thing we need to define in this button variant is the props variant, the props size as well. Right? we are passing these things in. Uh, since we're grabbing it with props like that, I'm going to need to say size like that. Variant and size variance. So, that's going to come from props.variant and also size Okay, so that should be correct. Uh, let's let's have a look. I'll go here. For the primary, I'll do a BG blue of 400. And for the destructive, I'll do a BG red of 400. Okay. So, you need to pass these down. Variant as well. Now, variance, my apologies. So, variant and the size. All right. So, all the different variants that you have. Now, finally, let's also type this out. Uh, so we actually get to see what's on props because so far everything we typed. So, if I do props dot, see, we're not really getting anything. So, let's head over here to the top. I'm going to create an interface for this. We're going to call it button props. I'm going to say extends and we can use the use render here dot component props. And we can pass in a generic here of type button. And there we go. And then to also get the variant variance, we can do variant props from CVA. And the type of here is going to be the button variants. And we're going to do curly brackets and just add a comma there at the end. Oops. I don't think we actually need the comma. There we go. And now we can simply type this by adding button props. Now here's the beauty of CVA. Not only you can create varants. Uh we have the types now here as well, but more importantly we have types on our app tsx. So I can head here and I can have all my different props, but I also have my variant prop. Look at that variant. And there's no way to mistype this now because it's all here. So I can do primary on that. I can come here and I can do a variant of destructive on that. And there we go. Look at that. It applies that nice red color already. How cool. So if we head back here, everything here still works. So as you can see, these get recognized as well. And the render prop here also gets recognized. Render. Cool. Now, why did the blue not apply here? We defined BG blue, but we have a BG red here at the top. So, we we're essentially having the same properties here, kind of having a conflict. So, this applied, but this never ended up applying. And you're going to see Shad Cenne as well and a bunch of other people that create these UI libraries also use a special tool to essentially merge these conflicts. You know, you might also have a situation where you go here in your app tsx and you want to override something. So you might go here and add a class name and you say bg amber of 500, right? And hit save. And look at that. Nothing happens. So it's up to you how you want to prioritize these. Uh but the little package that we're going to use is called tailwind merge. So let's install that. Let's head over to the package json. So let's head here. We're going to say mpmi. We're going to say tailwind merge. Let's run this back up. And again, this is really popular that you're going to see is here. Whether you're using graphics or base UI is we're going to take this variance now and wrap it into that tailwind when merge. So this is how that's going to look like. We're going to say TV merge. Let me actually check how that gets imported really quickly. Uh let's go to the top here and we import TV merge like that from tailwind merge. So all these button variants are going to get wrapped now. TV merge. We're going to do a parentheses and another parenthesis here. There we go. And just doing that should solve that issue. So now as you can see that conflict gets resolved and the variant takes the priority. However, even if you want to override this, we can solve that by merging it with our class name that we might pass down through props. So we can go here to the end and we can say props do class name. So nothing happens. It still works how we intended it to work. However, now we can go back to the app tsx and let's say I end up wanting to change something here. My class name here is always going to override it. So 900. Hit save. And look at that. It works. So there we go. We learned a bunch about base UI, how to set up and render out a component, but also about CVA and kind of the benefits of having this tailwind merge class. So, hope you enjoy this. In the next episode, we will actually start setting up the styling for the button. So, I'll see you then. Okay, let's start creating our new morphic effect on our buttons. So, we're pretty much going to remake this whole section here, our base styles and also the varants. So, we'll keep this inline flex justify and item center, but we'll get rid of the BG red that we added here at the top. Let's remove that. And let's also make sure in our app tsx we don't have any other class names attached to these. Perfect. Okay. So let's head back to the top and let's add some base styles here that are really useful. One is when I hover over this I want it to essentially show me the cursor of pointer. Right now the cursor stays the same. Uh which is not what we want. So, cursor pointer. That's how you add it. And now when we hover over, as you can see, we get that nice pointer. Okay. Now, also when we hover over this, I want the opacity to go down slightly. So, I can change this to something like 90. And we might come back and adjust this depending how this looks. But look at that. When we hover, we get that nice fade. Okay. Let's also start getting rid of this outline here. Now, you might heard that there's two properties, outline and ring. And as far as I know, you have more customizability with the ring rather than the outline. And previously, the outline also didn't like respect the border radius, but now it does. But I still believe you can do a tad bit more with uh ring rather than outline. So, we're going to use that. You're going to see shaten also use that by default. So, we're going to target the focus visible here. So whenever the element is visible, so when you hit tab, for example, you're going to get that highlight. So I'm gonna say let's do ring of foreground here. All right, let's hit save. You're not going to see anything yet because we also need to add a focus visible of ring two. That's like the thickness of it. And you can kind of see it now. uh but it's kind of overlaid on top there. As you can see, we also have a border there. That white border that is kind of blocking it. So, what we can do is also do focus visible of ring offset. And I'm going to set this to two. Let's hit save. And now it's nicely on the outside there. All right. So, that looks much much better. Cool. Okay. So, there we go. We got that. But we want to get rid of that outline on the inside. So let's do focus visible. And we're going to say outline none. Let's do rounded. And we'll try let's try Excel by default. There we go. So as you can see the outline also kind of goes after it, which is really nice. Perfect. So we got that. Let's also add a border. I'm going to do three here. And the border color, we're going to set a custom one up here, but let's just do the foreground for now. There we go. So, we got that border of foreground. Now, let's set up some more colors so we can start having that really cool neomorphism effect. And let's just do the light colors for now. And then we can get back to doing the dark mode when we when we're going to implement that. So we have the primary. Let's do a destructive. So we're going to say color. Let's do red of 600. Let's do a warning as well. So that's going to be color. We're going to pick orange. And for the effect that we want to achieve, we also want basically to create two shadows. So let's create a shadow. I'm going to create a raised one. And then we're going to create one where it's like has the effect where it gets like pushed in. So let's create that. And let's also create a shadow insert. Now we're going to get back to these because we're going to need to write quite a bit. So, for now, let's just finish these up. I'm also going to have a muted here, which is going to be a zinc of 300. Okay. So, just a bit of an offset from the background color here. Just a shade up. And then for the text as well, which is going to be the foreground color, I'm going to do color muted foreground. So, this is going to be color zinc. And I'll do 600 for this. Okay. So, how are we gonna create these shadows? The way we're going to create them is we are essentially gonna overlay multiple shadows on top of each other. First of all, we are going to have a highlight and a shadow. So, I'm going to create actually a variable for those two as well. So, we're going to keep this simple. I'm just going to use an RGBA here. So 00 0 that's black. And then you can control the opacity here. So I'm going to do 15% opacity. And then we have a highlight. And for this one we can just simply do a of white. So now here for the shadow raised we can do a two pixel 2 pixel 6 pixel. So two pixel 2 pixel here basically dictates the position of this. So two pixels to the right and two pixels to the bottom here this side. And then we need to add the color. So we can just say color shadow. I'm going to add a comma here. Make sure you spell this correctly as well. I did two Rs there again. And I basically want to do the same but for the opposite side. And then we can do the highlight here. Okay, there we go. So that's one. And then we can go here for the second one. And for this one, I'm going to do an inset. So, it's going to be on the inside of the button. So, same values. And we should be able to test these out. I'm going to set a marker here. I'll go to the button. Let's set here to the top. And for now, just here at the end. Uh, I'm going to say that the border is going to have a color of background There we go. So, it just looks transparent now. What this is going to do is the effect of the shadows is going to happen on the outside which kind of makes the border come into view and it's going to look really cool for now. Also, let's just get rid of the background colors here. We'll come back to this and we'll just set a default here which is going to be of background. Okay, let's head back here and let's apply our shadows. So shadow raised and look at that we got the neomorphism effect. So as you can see we got the highlights there showing up nicely and the shadows are bringing this out. Now again kind of the problem that we have with this is it's quite hard in terms of accessibility and contrast. This can cause quite a bit of problems. So to fix this uh we are going to add some more coloring to this. So let's go here at the top and I'm going to add a linear gradient to this. So I'm going to say bg linear to top left. And then on each variant I'm going to customize them differently. So for the primary I'm going to say text primary and we also turns blue. And then I'm going to say from primary and I'm going to lower the opacity to five. And two, I'm going to up the opacity up to 25. There we go. So now there's a nice clean separation of like where the button is. And having this border kind of keeps that effect as well, which is really nice. Uh, if we didn't have this, it'd be a bit harder again to tell because the blue doesn't really mix too well with the highlights and the shadows. It just ends up looking quite strange if we don't have this. So, if I remove this for a second, no borders there. As you can see, that just ends up looking pretty weird. So, this way we maintain accessibility and it also looks pretty cool. Okay, so we got that. And now what we can do is do it for the destructive as well. So text destructive. And we go. We got that red. I'm going to do the same primary five to primary 25. Sorry, destructive here. Nice. So, we got two nice looking buttons. And let's also hook up the warning. I'll copy these styles over. You can paste it as well. So, for the warning, we pretty much have the same. And then for the default, we can essentially do a combination of the background color and our highlight color like that. So, from background to highlight. Again, you can kind of customize it any way you want. So if we have a look at this, go back to our app psx and let's just render two more out. So we'll have one that's default. So we don't need to define a variant. And there it is. So as you can see, the border kind of separates a little bit for us. And at the bottom here, let's also do the one that has the warning. Now, there's a few other things that we need to keep in consideration here. For example, what if the button is disabled. So, you might have something like this. Uh let's change this to primary for example, but I'll add a disabled prop on it. As you can see, it looks the same, which is not the behavior we want. So, let's go back to the button. Go to the top. gonna go here and I'm gonna say let's see we're gonna say disabled. So you can use this prop and say opacity. We'll lower that down to 50. So there we go. Looks disabled. And I also want to change the pointer on this. So disabled pointer events none. There we go. So it doesn't look like we can click it at all. Lovely. Uh, anything else that we might want to consider to add is maybe the font here. We can do a font medium. There we go. That just makes it look a bit clearer. Another thing that we might consider is we might want to add another prop here, another type of variant, which is going to be the shape because we might actually want to have a button that kind of looks like a circle where we just render out an icon. So, let's do the default. We can set the rounded to what we had. I'll just leave it empty. We can just move it actually from up here somewhere. Let's see where we had that rounded. Here we go. Rounded excel. So, let's actually move that. Move it here. And then I'll also have another one called circle. And this can be a rounded a full. There we go. All right. So, we have another prop. Now, we've got to make sure to pass that down here. shape. That's going to come from props.shape. Cool. All right, that's looking good to me. Let me see if there's anything else that we might have potentially missed. Oh, let's try to do the Let's see why this doesn't apply now anymore. See, when you don't have in the default variance here the shape as well, then the rounded actually doesn't apply. See how we went back to just looking like a normal button without any roundedness. So, we actually have to go here to the default variance and say, "Hey, the shape should be this default." And now we're back to where we were. Awesome. Okay. So, we are looking pretty good. Now, let's try the inset as well. Basically, when this button becomes active, I want this to have the shadow inset. And when I click on this, doesn't seem to work properly. The other one disappears, which is fine, but I don't see the inside of this. So, something we messed something up. Let's head back to here. Okay, let's double check. So, we have the comma there. That looks fine. Here we have inset. Here we go. This is these Rs. We keep messing them up. Let's hit save. There we go. So, see how you got that nice little inset going on now. Great. Okay, cool. Now, what I want to do is animate this as well. However, if you try to do this like let's say go here and say add a transition of all with a duration. Let's put this at 250 for example. Um, it's not going to actually work. Let's also add an ease out. Let's hit save. See how that doesn't work at all. It doesn't work because we're essentially changing the shadows that we have. So, to make it work, you essentially want to have the same kind of shadows in both properties. So for example here we have two insets and we forgot the inset here as well. There we go. Now we get to see the highlight. See how here we have two insets. However, here we just have two outer shadows. To make this work, what we can do is simply go here and define these two insets even though we might not want to use the effect. So you can just put them with zero values. So you you can just say inset 0 pixels 0 pixels 0 pixel with a var shadow inset 0 pixels 0 pixels 0 pixels with a var of color highlights and that's it. So just define it. And then we missed the little comma And then same for the other one. Okay, let's Why does Why is this not working? One insert. Um, comma shouldn't be there. Comma should be here. Okay. All right. So there you can pause the video a little bit because this is quite a bit here. Make sure you use commas in between the shadows and at the end you want the semicolon. So we added these here initially and then here we also want to define these ones the other ones right. So let's go here. We can just do 0 pixels, 0 pixels, 0 pixel, color shadow, 0 pixels, 0 pixels, 0 pixels, var color highlight, comma. That's it. Save. And look at that. You got that cool effect. However, for the inset one here, I still kind of want to keep a little bit of that shadow raised. and the shadow highlight here because again, see how we're again having problems with accessibility and it's quite hard to see. That's why we want to make sure to keep a little bit of that value here. So, we're just going to do a really reduced version of it. So, here on the shadow inset, let's do one pixel here. One, one, one, one, and one. Let's try two pixels here instead for the blur. And we actually need to do minus on these. Okay, let's see if that two pixels looks a bit better. And it does. Look, we still have good enough contrast there. And it just squeezes it a tad bit more down. Now, if you find out that that the animations are still not working, that's because the ordering here matters quite a bit. On the shadow raised, we have the insets defined at the top. Whereas on the shadow inset, we have the other values defined at the top, not the insets. So, we just need to reorder these. So, for the shadow rays, we can just grab both of these insets and move it below our big shadows and highlights here. So, grab this top portion with the two insets. cut it. Go here to the end. Add a comma rather than the semicolon. And let's paste it here. And then close it with a semicolon. All right. So, we're just made sure that the orders are correct for these and these. Now, we should be able to click. And look at that. You get a nice animation with the highlights and everything. And that just feels really satisfying to click in. Amazing. Now, one last little thing that we can do is change up the size a little bit for the button. So, here we can say when the button is active, we can just scale it down to something like 97%. And there we go. We got a nice effect where it looks like it's getting a bit pushed in. Awesome job. Now again, you can kind of customize this if you want to increase the shadow or the intensity of it, but I'm quite happy with how that looks. All right, so there is our button done. Now, it'd be nice to kind of see how this looks on dark mode as well, which is kind of the preferred way I like uh these to look. Uh so in the next episode, we'll get that implemented. I'll see you there. to create our dark mode. I'm actually going to use chaten's guide here uh because it's really simple and straightforward and we can get up and running really quickly. So, if you go on UI shaden.com, we'll head over to the menu and we'll scroll down all the way to dark mode here. And now we are using VIT. Uh but this works for Nex.js Astro Remix as well. Let's go to VIT. And as you can see, it gives us this team provider uh that we can use. So let's simply copy this over. We'll make some more space. And I'll define it in a new folder. Call it providers. And let's call this team provider. Okay, let's paste it in there. So, let's just quickly look through it. So, it's going to use React's context to essentially switch between dark and light mode. Um, just has two states. So, the team name and the set team. And that's pretty much it. It also saves it to local storage so it'll know how to get it and also how to set it. And it basically checks the preferred color scheme uh on the HTML to see if it's on dark or light mode. And that's it. Now let's go down here and see the next step is to essentially wrap all your children in this theme provider. So to do that in vit we can go over to the main tag here. As you can see that's where our app is. We can say team provider. Take the app paste it in there. Let's go here. And now we can pass in the default team as well. Let's do dark by default. I like how that looks. And the storage key as well, which is vit UI. Okay, I think they use this to essentially save it in local storage as like the key name. Okay, so if we head back here, look at that. turned into dark mode. However, that looks pretty pretty darn horrendous. So, the reason is we just need to essentially fix up the colors. We haven't really done that. So, let's go to index CSS. Let's head here to the dark mode. So, color background. That's fine. This is fine. We'll need to define different highlights and shadows. So for the shadow now we'll do a bigger value. We'll do 0.6. There we go. Even 0.7 just so it pops out a bit more. For the highlight, let's do an RGBA of 0.15, so it's not so intense. And here we need to do 255 because 0000 is black. There we go. So now it pops out really nicely. All right, good. So that that's looking much better. We just need to adjust some of the colors as well. So I'm happy with how this looks like. However, the other ones don't look too good. So let's do color destructive. So, we'll just do 400 across the board for the warning as well. Orange of 400. Let me make sure I do one R here. There we go. So, there's much more contrast now. It's It's really easy to see. I might actually increase this highlight a little bit here. Uh, but it looks pretty good for now. We'll see how it kind of comes together. Let's do the color muted as well. So, we'll do a zinc of 700 on this and a muted foreground. We'll do a zinc of 400. Okay. Nice. Finally, let's also implement a little navbar here to give us the functionality to toggle these two. I'll open the side panel. Create a new component here. I'll call it nav tsx. I'll do export default function nav. I'll return a nav that's going to contain basically the title. Let's just do H1 neomorphism UI and also the toggle icon. We can actually get that from here. let's just render out a button. We can say button. We can just use our own. Now, I'll just say light here for now. And we can actually, it's up to you how you want to do it. I guess we could use the little icons from Lucid React. That's going to look a bit nicer. There we go. Let's import those actually. So here rather than doing the text instead we will render out these two. Okay. And the styles these have is uh basically a size right so 1.2 1.2 on the width and then they're going to get rotated around. Okay perfect. And here on the nav let's also add a class name. We'll do a py of four and a px of 12 for now. We'll come back to this and see how it looks. Let's go to the app tsx and render this out. Let's import the nav. Let's save. And there it is. Look at that. We got our nice little button and our neomorphism UI text. So now we can kind of style this up a little bit. We can add a class name to the H1. Make the font medium, maybe even bold. We'll add a flex to this with a justify of between. There we go. And we also want to add an items of center because look at that. They're not really in the same line. There we go. That looks pretty good. Uh maybe we can increase the py here to something like eight. All right, that looks cool. And yeah, pretty happy with that. We can also test out this now here to see if we can get the circle actually on this. So let's do variant. Not variant. I think we named it shape. Let's do circle. Look at that. We got a nice circle. Something is still looking a tad bit off Looks like it's it's not really a circle. It's more like a pancake. And the reason is it looks like it's this padding X that gets added there. So we need to also add the size of icon that we created because that doesn't have any padding on it. So size of icon. And look at that. Now we have a perfect circle. That looks awesome. Okay, cool. To actually get this to toggle, let's head up here to the top. We can import this. Let me show you here from Shatien. We can import the set team. Let's go here. Import that. and for the use theme. And essentially when we click on the button, we want to toggle between the two. as you can see, we can they they're using it here with a drop-down menu, but the way we're going to do it is we're going to put it on each icon instead. So on the sun icon I want to do on click run a function. I'm going to set the theme over to dark and then on the moon we want to set it to light. So on click set theme over to light. You can also do it on the button here. for example, you can just simply import the team and check that. Uh, but this will work just fine. Okay, so let's give that a go. Let's click on that. And look at that. Ch. Actually, it's probably better to do it on the button because I have to specifically click on the inside of that for it to activate. Uh, which can be quite tough to do. So, let's actually do that. Get rid of it from here. Go on the button. Do an on click. Run a function. Let's import the team and say if team triple equals to light, then set the theme over to dark. Otherwise, set team theme over to light. Okay, let's give that a crack. Click. And there we go. Look at that. We get that nice style change. However, the icon doesn't change. So, for that, we can just say theme question mark. Then we can just render this out. So we can do a turnary operator. So if this equals to light then we want to do this icon. Otherwise we can do this icon. Okay. Look at that. I can click now and they both that goes white actually. So you can't actually even see it. Now as you can see the white mode still doesn't work here. So we don't see the icon. And the problem is that it doesn't recognize where the dark and the light actually is. So this directive never gets recognized here. So in Tailwind to actually enable that and to toggle it manually, we need to add this custom variant here that basically says, hey, look for everywhere where we have this dark and just grab everything and apply that color scheme to it. So what we can do is just head over to our CSS, go to the top here, paste that in, and now it should work all nicely. Have a look at that. and toggle between them. We can also add the warning color to it if you want. So, let's go here and I'll add a warning instead of black. Hit save. And there we go. We have it all nicely styled up. There we go. Awesome. That's our nav and our dark mode fully enabled. I'll keep it on dark mode because I much prefer it. And we're going to move forward with all of this. Before we get into creating different components, let's just kind of finalize the style for uh this new morphism effect. For one, I still want to give a bit more contrast here to separate the buttons from the background. So to do that, what I'm going to do is in the CSS file here, I want to essentially adjust sorry in the in the button file here, I want to adjust the border. So it's just a bit darker than what we have here. So for now if you have a look if we have a look for the border we accident accidentally also added two borders here. This border foreground doesn't really do anything because we have border background added afterwards. So if you remove this border foreground nothing is going to change. So if we hit save as you can see everything still looks the same. But I essentially want to control this with a different variable. So let's name the variable border. So we can do border border here. That's it. save. For now, it's just going to turn uh like that normal. Let's head over to our CSS and define that. So, let's start with the dark one. We can head here to the bottom and I'm going to say color border. I'm going to do a variable and I'm just going to go one shade darker than the background here. So, color uh zinc 950. That's as dark as you can go on on uh on dark mode. So, if we hit save, color border. Okay, for some reason, this didn't take effect. Uh, but let's add the other one up here, too. We'll do dash color border. I'm going to say variable, and I'll do one shade lighter here. So, not 200, but 100. So, color zinc 100. And let's hit save. And there we go. Look at that. We have a darker one and here we have a lighter one. So it just kind of separates it a tad bit more than what we had before. Another cool little thing that you can do is also add a little inside highlight here to the buttons. So I'm going to define a new variable for that. I'll call it edge color edge. I'm going to do an RGBA of 0 0 sorry 255 255 255 for white and 0.1 here for the value. Let's hit save. And the reason why I'm not using this highlight again is because this has opacity. So actually bring kind of the colors through. So I'll just go here to the shadow raised and I'll add a new property to the end. an inset of one pixels, one pixels, two pixels, variable of color edge. Hit save. And look at that. It's very subtle, but it adds a little inset shadow on the inside, which makes it look pretty cool. It's probably a bit more prevalent here on the uh circular button, but just adds a tad bit more to the effect. I really, really like it. One more small thing, we can adjust maybe the uh the highlighting here a little bit to kind of separate it even more. So for the highlight, maybe we can bring this value up to 0.2. There we go. Just to make it a little bit more intense. Uh so it's easier to see where that border starts. I think that looks a tad bit better. Uh same for the shadow here. We can lower that to 0.75. Okay, cool. I like that much better. Now for the light mode, let's head up here. Let's double check everything is fine. So here for the highlight, we just used white. So that's as as bright as we can go there. And then for the shadow, maybe we can lower this to 0.2 as well. There we go. So that just adds a tad bit more separation now for us. Great. Finally, let's also adjust this button here because I think we used like the background color for it, but we should just use our muted color and kind of match the aesthetic that we had here. Uh, so as you can see, it kind of looks off from the rest of the buttons. So, instead of doing that, we can do a from muted of five just like we had here to a muted of five, 25, sorry. And there we go. Now it looks a bit more in line with everything else that we have. All right, there we go. So, this is the style we're going to keep and move forward with and we are going to apply it to everything else that we have. Awesome. I'll catch you in the next episode. All right. In this episode, we will start creating our card component. This is a key component that you're going to see used everywhere to kind of group stuff together. As you can see on the course platform here uh we use it essentially to group different sections. So this is the basically choose your path to learn and we have all the different things that you can do. So courses right CSS challenges also blog posts. So it's a good way to kind of categorize everything together here as well. We have two sections that are grouped with a card for the FAQ section as well. We have four different cards. So it's a really important component they are going to be using on every website pretty much. Let's hook this up. So let's open the side panel. We'll head over to the component section and we are going to create a new card tsx component. Cool. Let's go in here. Uh we'll export it. So export default function. Let's call this a card. Actually, let's not export it as a default uh because we're going to create a couple of different components here. A card header, a card title, description, footer. There's a couple of different parts that we can kind of compose together. So, let's just export function card. Okay, we'll have our props here, which we will name in a second. There we go. And if you remember how we did it on the button, we have an element. We'll use a use render from base UI. The default tag name here is just going to be a simple div. We'll have our render as well which we will need to name. And then we have our props which we will need that merged props uh which we also don't have. Okay. So let's type this props quickly here. We'll say card props. We'll extend this again. We have this available from use render here from base UI. It's going to be a component props. That's a type of div. Add a comma here. And we also need the variant props. Now, we haven't defined a variant yet, but that's fine. We will. Let's do it now. Let's call this const card variant variance I should say plural. We'll use our CVA here class variance authority. And for now we'll keep it simple. I just add a rounded of 2 Excel and define our variance. So I'll have two different variants here for the card. We have a default one that's just going to have a shadow of raised. And I also want a inset version of this which will have the shadow of inset. That's it. We'll keep it super simple. Make sure you also define the default variance here so we know which one will apply. In our case, we want the default. You could also name this raised if you want. If you don't want to have default here as well. So raised like that. And then you can put raised as the default. Let's do it like that. And now here for the variant props, we can simply pass it down. So it's a type of card variants. There we go. You don't need the parentheses here, but you need the curly brackets at the end. There we go. It's defined. So we can pass it in as a type here. It's a type of card props. And now that we have that defined, we can head here to the render and we can say this is props. render. And for the merge props, let's create Set that equal to we'll import the merge We can pass all the props here. And the one that we want to merge, we can do it in curly brackets like this. Right? So all we want to modify here is the class name, right? Because we have the different variants or maybe different class names that we want to pass through. So that's going to be of type card variants and here we need the variant which is props.variant and and that should be good. Okay, so we are passing the merge props down as well. And then finally here, we just need to return the element tag. Cool. Let's hit save and we can already test this out. Uh let's head over to the app tsx and render out one of those cards. So I'll import the card component. And for now, I'll just render out a H1. Hello. And let's also do a quick paragraph. Hit save. And there it is. All right, we can see it there. Now, there's still a couple of adjustments that we need. For now, I'll simply wrap this in the div just so it's not so tight around the the borders there. Let's paste it in here. I'll just add a little margin. Class name MX of four. And let's al let's just do an M of four. Six. There we go. just to bring it down a bit so we can see it a bit better. Okay. So, as you can see, we have that problem now with the with the contrast and like this being separated. So, again, that's why we kind of need this border. Otherwise, you have this accessibility issue. So, let's head over to the card, go to the top here, and let's define some styles. So we'll do a border of three and a border of border. And there we go. Now we have that nice clean separation. Cool. All right. So that's one here. And kind of the benefit of having this one set up now is that we can kind of duplicate this a couple of times for the rest of them. So we don't have to manually type everything out here. So basically everything from the export function card here. We'll grab the interface as well and the variance here. Copy everything over and we'll paste it down here below. Paste that down there. And let's rename this. We'll call it card header. So all we need to do is update some of these stuff. So, card header variants. Here we'll do card header props. Card header variants. We'll change the export function to card header. Make sure you pass down here the props as well. Card header props. card header variants. And I believe that should be it. So there we go. We created a whole new one. Now, this is going to have a couple of different properties here. So let's go up here, change this. We'll do a flex flex of call space Y of 1.5 and a padding of six. And actually, we're not even going to need any of this stuff here for the variance. We'll keep it nice and simple. So, let's just get rid of everything and keep it a one line. Now, here for the card variants, uh, we can just keep this empty and that should be fine. There we go. So, that's the card header done as well. Let's just copy this because it's much shorter now since we're not defining any variants inside here. Let's cut that. And we'll need three more. We'll do a card title. So, let's change this to card This will be card title variants. There we go. This will be card title Card title variants. Card title props. Okay, let's see. And then here we also need to change the name of this. We'll…

Transcript truncated. Watch the full video for the complete content.

Get daily recaps from
developedbyed

AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.