Design Systems with Storybook, v2

Adding Dark Mode Theme

Steve Kinney

Steve Kinney

Design Systems with Storybook, v2

Check out a free preview of the full Design Systems with Storybook, v2 course

The "Adding Dark Mode Theme" Lesson is part of the full, Design Systems with Storybook, v2 course featured in this preview video. Here's what you'd learn in this lesson:

Steve configures dark theme support for Tailwind CSS. Storybook decorators are introduced and used to add a theme switcher to the preview interface. The theme switcher modifies the configured data attribute to switch themes.


Transcript from the "Adding Dark Mode Theme" Lesson

>> Let's look at this top bar and see some of the options we have. We've got a refresh button that does what you think it does. I'm not gonna waste our time on zooming in and out. We've got these light and dark mode, you can kind of see here as well, there's nothing that supports it.

This is just the background though, so you have different backgrounds if you want to see how it contrasts with different things. We've got the ability to have a grid, I've never used that on purpose in my life, but it's there. This is super important different viewports, and we'll talk a little bit like how to force, a given story into a viewport because, this button doesn't really matter.

But when I get to, if I was doing more like, above and beyond the design system portion when we're doing kind of like, molecules, organisms, parts of design systems, like if I did whole pages in here or like larger responsive like elements, you can actually one, easily go see that thing in isolation, right?

Two, you can force like a story to be in a various viewport, which is great for your visual regression tests, right? Because nobody likes that world where they make a tweak for a hotfix for a bug and they end up breaking something on mobile, so on and so forth.

Because I definitely didn't get bitten by that bug where the CEO tried to pull up our UI on his Android phone last week at all. So, and you can actually change some of the, you can rotate it, so on and so forth, right? You've got this measurement, which is kind of like the Chrome DevTools, which is pretty cool.

And you've got this outline around it, again, I'd love to tell you that I've used that more than once in my life. This is an add on for the accessibility, so we'll talk about that later. You can also have links and fullscreen it and all that kind of fun stuff as well.

So what we wanna do is we wanna add the themes plugin, right? And we also, I need to do a little bit of which amounts to structure dark mode. There are two ish, three technically, let's go with two, philosophical ways of implementing dark mode. One is you would like to provide a toggle, right?

That lets people turn dark mode on or off, right? That sounds very, it doesn't even sound complicated. That is basically you just put a CSS class or a data attribute on the body of your document and then either, toggling on or off. The other one is, media queries, right?

Like the idea of their whole OS is set to dark mode, then you can do that as well. We chose to have a toggle mostly because ours is still in beta and I wanted a toggle. [LAUGH] Right, so that one could toggle it on and off because I'm not totally confident that we got every edge case just yet.

I really definitely like, where you started but for all that dark mode stuff and it definitely, was invaluable, but then also exposed that, it's a lot harder than we thought. But we'll talk about some of the strategies around that in a second. So we do need to do a little bit of both, both a little bit of tailwind tweaks, as well as some storybook tweaks.

And so we'll cover those both together. Again, if you just want to use the media query, there's nothing to do on the tail inside. And if you write your own bespoke CSS, there's both nothing to do and everything to do simultaneously. So we'll just talk about the little piece of a tail and tweak that we need to do.

Here, which is to say how dark mode works, so by default they use the media query. And so what we wanna say is that it's a class. And then for reasons I don't understand, I chose to use a data attribute. I know why you chose to use a data attribute.

So instead of using dark mode class, we use a data attribute of like data, mode is dark or you can data theme is dark. The reason we did that is because when we started, I found out that we used the class dark on various elements to insinuate, this is a card, this is a dark card even in light mode, and all sorts of stuff broke.

So I did this as a data attribute, because I was transitioning a code base from existing with only one mode to having two. You could choose to just use a CSS class, it doesn't really matter. But so I'm gonna say, this has got to be a string, I'll say data.

This is just, it's any selector that we would want here and mine is set to mode. So any selector goes here. So we're gonna say, hey, tailwind you're gonna do dark mode with a class really means CSS selector. And this is the CSS selector that you're gonna use when using that functionality.

If you have your own CSS then, you don't need to do the darkMode tweak here, and we'll show how to do it in a second. This is the only tailwind specific part that we're gonna cover right now, sweet. And we've got that in place, so then we're gonna do this.

We're gonna add in this idea of the themes. And so I'll just make a new tab here real quick and there's two ways to do this. You could do an npm install, and then add it in yourself into that main.ts. Or you could do this mpx storybook at latest, and we say add @storybook.

Lots of opportunities for typos here. Add storybook/addon-themes. All this does is it does two things. It installs it, and then it adds it to that main.ts. It's already installed on my end, so we've got that here. Let's go into main.ts, we've got the add on themes, cool, cool, cool.

There are some options that it will give you if it's the very first time you're installing it, we can say like how you want this to work. A concept that we're gonna talk about a little bit later is this idea of decorators, right? But we'll see it a little bit in this global file.

Which is a decorator is something that you wanna wrap that story in. Reasons that you would use decorators, and we'll see the first one later, is let's say that thing needs the context API because you're using a motion or some CSS and JS framework that uses a React theme or a self theme context for the theming, then you would need it.

If you want to just surround something in, A list items in a larger list or anything you want to do, anything you want to surround every story with, you could use a decorator for. And all it does is it just gives you the ability to put a parent over a given story.

You would put it in preview.ts if you wanted it to be, either main or preview.ts if you wanted it to be for every story, you can put on the meta for just that set of stories. You can do an individual story, it doesn't really matter. So we've got the add-on themes in here.

And next we are going to go ahead and add a decorator in here as well. I'm actually gonna import what I need first, and there's just the @storybook/ add-on themes has some utility methods, and you can take a lucky guess what they do. So I'm gonna do import and I'm gonna do the trick of @storybook/addon-themes.

And the reason I do that first is so that I get intellisense in here. And so you can see there's three helpers in here with ThemeByClass. Anyone wanna take a lucky guess what that one does? WithThemeByData attribute, and withThemeFromJSXProvider for those of you who love your CSS and JS, cool.

And then all we're gonna say here is, decorators. And you can pass it in by itself, but I need to give it some options in this case. So I'm gonna say that my defaultTheme, Is light. Now clearly for a set of stories, you can take this down one level and do dark so on and so forth.

And I'm gonna say I have two themes. Light and what that ought to be. In this case, light is light and dark is dark. But in my actual code base, it's day and night because we were clever and we thought it was cute at the time, and now I live with it.

And then what the attribute actually is in this case, so in this case, I think, TypeScript is gonna get angry with me if I remember correctly but no. So we've got the attribute name in there as well. And I think that should be what I need to get that running, so I've got it.

The things I need to do was make sure it's in this array here and then actually have the decorator go around every single story saying, hey, I've got themes, these are my themes. Here's the default, here's the data attribute that you need to swap the theme, and everything you need to know.

And then that will be inherited by every single story. There it is, light theme. Turn it off and turn it back on was the answer to the, what went wrong there, cool. So now we have dark mode and we have light mode. Again, there's not necessarily a lot of tailwind need to know that you need to know.

The only where that dark mode is currently defining anything is tailwind comes, we actually mostly replace our tailwind themes, I'm not using a lot from tailwind. One of the things I like it for is for both responsive breakpoints and themes, I can just do dark colon, small colon, and I have to write media queries.

And the idea that it calls out any CSS class we're not using, that's the kind of large reason we're using it today. But yeah, so dark modes just changes right now the text and the background color. Mark.
>> Have you ever needed more than two themes?
>> We will.

Right now we have light and dark mode, and I'll show you a strategy that we're using for that right after in a little bit, so we plan on adding high contrast mode for accessibility issues. And then, possibly, our design language happens to be predominantly black and white with a little bit of indigo.

So high contrast mode is a few places where we need to do some tweaks. But for color blindness, we don't have a really big surface area because our designers happen to like black and white as the theme. So yeah, for us it's like, I used to work on a product where the theming was a thing that we provided to the end user and they could put it whatever theme they want in there.

I will never mention that to our current customers cuz they'll ask for it and then I will have to live with it. So, for us, light, dark, high contrast are the ones. But like we said before, if you are a company that's made lots of acquisitions and you need to have a theme for every different brand, so on and so forth, you might end up with more than one.

>> Using the toggle that was in there already, not the one we just created.
>> Yeah.
>> Overrode our light dark theme in the top. So the one that comes for default?
>> Yeah.
>> On the top, if that's set, you have to hit clear-
>> Interesting.
>> Selection.

>> Maybe that was my issue to too.
>> [INAUDIBLE] To that and then, yeah, otherwise that didn't-
>> Yeah, the background was set. I was probably messing around with that before and there's no, yeah, I didn't clear it out and then turn it off and turn it back on.

Fix that because it's stored in the URL, but yeah, that's an interesting point. Because I was like just showing off that you can change the background as the tour, I set a background and then you do need to make sure you clear that background especially when my dark mode presently only includes a background, right?

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now