# Awwwards Worthy Dark Mode Toggle with React and Framer Motion

## Метаданные

- **Канал:** Tom Is Loading
- **YouTube:** https://www.youtube.com/watch?v=MJ38jmK0NG4
- **Дата:** 06.05.2026
- **Длительность:** 15:42
- **Просмотры:** 513

## Описание

Animated UI components for React, Tailwind CSS, Framer Motion & More ✨ https://www.hover.dev

Normal dark mode toggles are lame! Thats why today we'll learn how to make custom, Dribbble/Awwwards worthy animated dark mode toggle using React, Tailwind CSS, and Motion for React (formerly Framer Motion).

📚 Project Links
Source code: https://gist.github.com/TomIsLoading/4bbbddd349eb68ff7252b86f4e305717

🔗 My Links
TikTok: https://www.tiktok.com/@tomisloading
Instagram: https://www.instagram.com/tomisloading/
GitHub: https://github.com/TomIsLoading
Twitter: https://twitter.com/TomIsLoading
Portfolio templates: https://tomisloading.gumroad.com/

Timeline:
0:00 - Introduction & Demo
1:22 - Let's write some code!
15:16 - Final product

## Содержание

### [0:00](https://www.youtube.com/watch?v=MJ38jmK0NG4) Introduction & Demo

Okay, so about 3 years ago at this point, it's kind of crazy to think it's been that long. Uh but back about 3 years ago, 2023-ish, is when I started working on both this YouTube channel as well as my component library. And one of the first things I ever built for this component library was this dark mode toggle right here. In fact, I think it was literally the first one. I think you can go back a couple years and look at my Twitter and actually find me posting about this little dark mode toggle that I made. So, if you're like me and you like to go through Dribbble and like kind of find cool designs and cool things that people are kind of making and designing and stuff. A couple years ago, one of the popular things was these dark mode toggles that have like kind of real elements that actually look like kind of day and night cycles. So, back then I made it and I always thought it was really cool, but I've kind of forgot about it for a while cuz I never really had a project that made sense that actually use it for me and for the stuff that I was working on just until about a week or two ago when I started working on this little like uh kind of split flap display maker thing that I've been kind of playing around with. What this actually does is not super important for this right now, but point being I thought visually my dark mode toggle kind of fit with the vibe for this project that I'm building. So, I got to use it. Made me kind of remember that it existed. Thought it was fun. And it's a also I think a pretty good kind of entry-level project into learning how Framer Motion works. So, I figured it'd be something that I could kind of pull out of the library. We could look over the code. We could kind of rebuild it from scratch. We'll do it horizontally instead of vertically cuz it's a little more useful. And like I mentioned, we'll do it with React, Tailwind CSS, and Framer Motion. So, let's jump into some

### [1:22](https://www.youtube.com/watch?v=MJ38jmK0NG4&t=82s) Let's write some code!

code. All right, so I've got the project actually opened up over here. I have everything actually kind of written out, but I'm going to go ahead and delete everything. So, now we're just down to the bare bones. We just have kind of this toggle wrapper component. The only like actual dependencies that I have installed are Framer Motion. At this point, it's I still say Framer Motion out of habit, but it's Motion React at this point. So, I have that installed and I also have an icon library installed just so I have access to kind of a star icon and a little cloud icon that we're going to use to like kind of embed inside of our little checkbox thing. But you can use whatever you want. You can use, you know, your own SVGs or however you want. You don't specifically need to use the React Icons library if you want to. Just, you know, npm install React Icons, you can use the exact same ones or use whatever you want. Realistically, you probably have like a dark mode kind of harness set up in your own project if you're doing this for real. In this case, I just wanted to kind of show this off, you know, as simply as I could, so I just have this little single dark mode toggle, but, you know, again, make it fit for your own architecture. You don't specifically need to do exactly like this. This is just kind of the easiest way to show like, "Okay, I have light mode, dark mode. " And then I'm kind of changing, you know, some colors based on whether or not it's light or it's dark. If you're doing this with, you know, Tailwind CSS in a Next. js project, and you actually have, you know, that specific setup of like the dark mode class, so you can do, you know, dark BG slate 50 versus or BG, you know, slate 900 versus slate 50, you can do it that way, but take it with a grain of salt. It's just kind of the basic setup that I have for this. And just with this basic setup that I have right now, we don't have any actual toggle components. This is kind of just a the wrapper around everything, but we can actually start adding those things in. So, let me see what I've got. Cool. Okay, so to start, let's just make a component to actually kind of wrap, you know, the actual dark mode toggle itself. That needs to take in these props for the dark and light mode. And this is going to be relatively simple, so that's why I'm kind of just pasting these in as we go. But all this is going to do is set our dark mode with a button to, you know, dark or light based on, you know, just toggling it back and forth. You could also use like an input with a type of checkbox, or you could set the role on this. I think I didn't actually set the role on this in this example, but you could go ahead and set the role to, let me see, yeah, we could set the role to switch for accessibility purposes. And then the classes on this are going to be relatively simple as well, so I'm just going to add a little bit of padding. I'm going to give it a set width. I'm making this one pretty big. You can make it smaller if you want, but, you know, just make it a little more visual in this case. Rounded full on both the edges, give it a little bit of shadow, and then a linear gradient. And then we can actually just specify that linear gradient based on whether or not, you know, we're in light mode or dark mode. So, I'm using this blue and sky color for light mode or just this indigo kind of fade for dark mode. If I now save that and add my dark mode toggle up here, see, there we go. Now, this doesn't have anything in it yet, but if I click this, I should still get kind of the dark mode switch. And if we scroll in a little bit, we should see that it has kind of this light fade based on whichever direction we're kind of doing it in. Awesome. So, that gives us the bulk of the kind of just wrapping component. And I think the next like most obvious thing here to add is the little thumb that kind of goes back and forth, which will give this its size. And it is another one of those things that is relatively simple compared to you know, how complex you might assume that moving, you know, animating something from one side of an element to another might be. Before I even add it, I'm just going to point out what we're actually doing here because I think it might kind of tell to a little bit of what we're doing. So, we have this button component. We're adding a class of flex on it, and then we're toggling justify start or end based on kind of the mode, right? So, this is kind of telling you if you're thinking about this before we add the thumb, that we're not going to be, you know, taking that the little thumb part and say, "Okay, absolute position to the right, then left, and animate in between. " Framer Motion actually has kind of a single prop that you can add to an element that says, "Hey, anytime this changes position, even with like a flex change, animate it from its previous position to its next position. " Which is super powerful. You can do all kinds of stuff with it, but the most basic version of it is something like what we're doing right here. So, inside of my button, I'm going to say I want a new component called thumb that is going to take in my mode. Down here, I'm going to define my thumb. Also going to take in my mode. You can see that my AI kind of knows ahead of time what I'm doing here. But just to give this kind of a basic version, this actually helps. Can remove this here. Copy a couple things from my old example and then explain them. Yeah, here we go. So, now we have a motion. div. If you've never used Framer Motion before, essentially how Framer Motion works is you can just append any normal HTML element with this motion. And that just gives you a bunch of kind of superpowered props which allow you to add animations and things. So in this case, we're going to ignore the layout prop for now, but I'm saying, "Okay, my transition whenever this changes, I want to take 0. 75 seconds using spring easing. " Technically, we can even leave that out. Let's just do the spring easing. Actually, don't exactly know how duration interplays a lot of the time with spring easing. There's a couple of other things. So you can use stiffness, damping, and mass are the three kind of fields whenever you're using spring easing. Which when I say spring easing, if you've ever seen an animation and it kind of like wiggles as it goes back and forth, that's what this does. It's not necessarily based strictly on a duration as much as it is like the weight of the object. We'll actually see that kind of come to life here in a second, but the more interesting thing here is this layout prop. So if I hover over this, it'll probably give us a little explanation of what this does. Here we go. So if true, this component will automatically animate to its new position when its layout changes. We can actually see this. I think if I just go like BG white here really quick. There we go. We're not going to keep that background white, but just to show you guys, when I click this now, it's automatically going to handle animating from one position to the next and I didn't have to do anything fancy, right? I didn't need to go in and tell it that like, "Okay, you're positioned to the right. " Then whenever I click this, I want you to figure out how far it is from one side to the other side and animate. It handles all of that on its own without you having to do anything fancy. That said, I'm not actually going to use BG white on this wrapping component. Well, honestly, now that I look back at what I wrote earlier, I probably can. So what we're going to do instead of doing the way I was originally doing this, I'm going to copy all of this. I'm going to put this inside of some template literals like this and then I'm just going to change the background color again kind of based on whether or not we're in dark mode or light mode. So let's save that. Let me just make sure this is kind of doing what I want. Yeah, that looks totally fine. And now if we analyze how this works in dark mode, it's pretty simple. We're just adding a kind of background color, but in light mode, I'm giving it a little bit of a gradient again and I'm adding a little extra animation with this little animate pulse right here. This is a default animation that comes with Tailwind CSS, which just does this little pulse animation that we're seeing over here. And then inside of this element, we can add kind of a sun center, and it gives us the illusion of kind of like the area around the sun, right? Like the part that the Well, why can't I think of the name of it? But like the little sun spots and stuff. Which we can actually then add the center part. So, instead of our motion that div like this, I'm going to open this up so we can actually put some content inside of this. Inside of here, we can say if mode Yeah, here we go. Is equal to light, we want to use the sun version. Else, moon spots version. We'll comment that out for now. We'll start by just adding our sun center. So, we'll come down here. Sun center. It's going to be very simple. It's just an absolutely positioned div, inset a little bit. So, inset by a few pixels from the outside of the element, rounded full, and then has just kind of a solid amber background. Which then Uh actually, now as I do this, I remember now why I had a separate div for this. So, I'm going to go back up here at one at just for a second. You'll see right now everything is kind of animating in and out. Which if you don't want the whole thing to kind of animate in and out with this opacity, undo this change that we did right here, or copy it for these colors, and instead come down here and just add an additional div, which itself has those same class names that we had above. Just this way, we'll actually layer it below it if that makes sense. So, now we have a separate div, absolute inset zero. This is what has the animate pulse on it specifically. That way, the whole thing isn't pulsing, just the background is pulsing, and the sun center kind of stays solid, right? So, if I scroll in over here, we'll see that the sun center still has it's not doing the same pulse animation. So, that in my opinion looks a little bit better. And that's it for the kind of sun side of the animation. On the moon side, though, I like to have these little kind of sun spots that animate in whenever we kind of go from one side to the other. So, we can see how that works. I have my stub right here. We'll come down here and actually make our new component called moon spots. I don't actually want what cursor is telling me I want right here. I'm just going to open up some fragments and we'll start by just making a single motion dot div. You can use a span, you can use whatever you want. And before I actually add the animation, let's just add the styling. So for this first one, we're going to give it some, you know, a size of three, rounded full, BG slate 300, which we can actually see this kind of popped up right here now, right? We have our little circle down here on the bottom, so you can kind of see like the craters that we're kind of trying to fake adding here. And all that I'm really doing is a positioning it at some random kind of spot inside of this element. So we can duplicate this a couple of times. We're going to want a couple of them. You can add as many as you want, I guess. And then with each of them, we're just going to slightly nudge them into a different position. So for this one, we'll do, say, bottom four, left one. And then for the last one, we can do, say, something like this, right two, top two. So now I have a couple of spots that are different sizes spread just kind of throughout the moon. So this is pretty nice as it is. It kind of gives the effect, but one extra little thing we could even do with these little sunspots, or the little moonspots, rather, is actually animate them in from the side whenever it kind of pops up, just to give it a little bit of additional motion. And to do that, with our motion divs that we have here, we can set the initial state, so we can say initial is equal to, say, we want X transform of like minus four pixels and then an opacity of zero. And then using the animate prop, which is kind of the second in tandem prop with this initial prop, is saying we want to animate from minus four to zero and then an opacity of one over some duration. So let's say, see what I did last time cuz I know it looked good. Copy this down. We'll say I want a transition of 0. 15 seconds, or a delay of 0. 15 seconds on this one with a duration of 350 milliseconds. And again, we can just kind of do, you can either do the same thing for all three of these and we can abstract it out if we wanted, or we could have them all be a little bit different. I think in my original one I had them all staggered a little bit just so it looked a little bit more natural. Yeah, so just a very slightly different delay. Same with all last one down here. And now we'll see whenever we animate this in, we get this nice little kind of shift in from the side from all of the little kind of spots. And at this point, I think that's it for the moon and the sun. The last piece is the little clouds and the little stars and things that kind of pop up in the background. So, we can scroll back up here to the top. I'm going to fold up the thumb. Right under the thumb is where we are going to then conditionally render our either our clouds or our stars. So, we'll do something like this. We'll say if it's light mode, we want to use our clouds. We'll come down here and actually make that component. Cursor is really wanting to kind of give me all the code right now. But now, the way that this is going to work again is pretty similar to what we just kind of did with the thumb only except for just animating once, we're going to animate it on loop. Again, staggering all the different little clouds in the different locations and stuff just based on what looks good, but we'll have it run infinitely. So, it'll animate from one side to the next, fading in, fading out, and then it'll go back to the beginning and kind of animate again. So, we'll say at a we'll go in motion. span. Inside of that to start, we'll just add kind of a cloud icon. I'm using again React icons, so you can use the same one if you use the same package. By default, that's just going to drop it in there, right there. And now you see it. But we don't want it just kind of positioned to one side. We want it absolutely positioned somewhere within kind of this element. So, in my case, I'm just going to go ahead and paste these classes in. There we go. So, absolutely positioned from the left, you know, 40 pixels, from the top 4 pixels. And then, as mentioned, we can just animate this. So, copy that in as well. I'm not going to have an initial prop in this one. I'm just going to pass in animate, but one little trick that you can do is inside of animate, you can pass a list of numbers or whatever it might be, a list of kind of keyframes, and Framer Motion is going to follow all of them all the way through. The one kind of gotcha here is these have to be kind of the same length. Same with the timing if you want it to be different timings between each of these. But in my case, I'm just saying, "Okay, I want it to go from -20 to -15, 10, 5, 0. " I guess I could technically just do this if I wanted. So, in this case, if I just wanted to, I could just do this. But, the problem is, I don't want to have opacity be kind of a linear curve. I want it to go from 0 up to full opacity, and then down a little bit, and then back up to full opacity, and then back down to 0. So, we can kind of watch this as it goes over here. It kind of fades in, fades down a little bit, fades back in, and then fades completely out, and then it runs infinitely. In this case, I'm saying, "Take 10 seconds, delay by a quarter of a second, and just repeat this over and over again. " So, now we can have multiple of these, stack them with different sizes, different amounts of delay and stuff, and we'll get this kind of parallaxing effect like you would get if you actually, you know, looked up at the clouds. So, I'm actually just going to paste in a couple more in here with different values, so we can see those kind of all starting to pop in now. And all of these are just very slight tweaks of the same thing between positioning and speed and things like that. But, all is essentially the same thing. So, now we'll see, if I'm on dark mode, I switch back to light mode, they all kind of fade in, and then they'll just kind of loop as they continue to go. And then, last but not least, we have our stars component. So, if I scroll up, we kind of stubbed that out up here, get uncomment that out, and create it down here. So, we'll move over to our moon, and I'll go ahead and paste in one of our stars. And again, you'll see this is doing something very similar. So, I'm kind of keyframing the scale and the opacity kind of from a little bit smaller up to full, back to small. I'm doing this infinitely on some set durations with, you know, a set easing function. And then, the styling is again just kind of absolutely positioning the star somewhere. It's not like it has to be in the same position. You can put them wherever you want. And then, we just copy paste all those things kind of over and over again. You just make as many as you want, and go as fast or slow, however you want to kind of rotate these things. You can add new little kind of bits of details and stuff. But

### [15:16](https://www.youtube.com/watch?v=MJ38jmK0NG4&t=916s) Final product

with that, we pretty much have our full component. Obviously, you could add a bunch of additional little details if you wanted. You could add some grass at the bottom down here and animate a little dude running across. But, these same little fundamentals, kind of what I'm actually trying to get across with a video like this, is that these basic little fundamental building blocks can give you a lot of kind of interesting motion in these small details on a website, which can be really fun. But, beyond that, that's pretty much it that I've got for today. If you got anything out of this, I would greatly appreciate a like and a subscribe. And beyond that, I will see you guys next time. Peace.

---
*Источник: https://ekstraktznaniy.ru/video/51684*