Epic Web Conf late-bird tickets are available now, hurry!

Get your tickets here

Join the community and network with other great web devs.

Time's up. The sale is over
Back to overview

Mark Dalgleish Chats About Vanilla Extract

Learn more about CSS Modules, CSS in JS, and Vanilla Extract!

There is a diverse range of philosophies when it comes to CSS. Settling on something that fits the needs of your team and application can be a real challenge. Mark Dalgleish, the co-creator of CSS Modules, has been working on an option that might make that choice less of a challenge!

Vanilla Extract is kind of like "CSS-modules in TypeScript", allowing you to write CSS in your TypeScript, with locally scoped variables, and generate static CSS files on runtime. If you're interested in getting a deeper look, as well hear more about design systems, CSS in JS, and CSS Modules, check out this episode!

Homework

Guests

Mark Dalgleish
Mark Dalgleish

Transcript

Kent C. Dodds (00:00):
Hello friends. This is your friend Kent C. Dodds, and I'm joined by my friend at Mark Dalgleish. I think I said your name wrong, Mark. Is that right?

Mark Dalgleish (00:08):
Yes. It's Dalgleish.

Kent C. Dodds (00:10):
Dalgleish, cool. Say hi, Mark.

Mark Dalgleish (00:12):
Hi everyone.

Kent C. Dodds (00:13):
I asked you to say hi, Mark, that's okay, so everyone's good too. I am excited to talk with Mark. Mark and I we've known each other for, goodness, as long as I've been, even before I did React, actually. Because I started using CSS Modules when I was in angular JS land. I think I may have been one of the first angular JS users to use CSS Modules actually. Because I don't think it was ever super widely used in the angular JS world.
But I jumped on board that so quick. I was so excited about CSS Modules. The reason that I mention that is because Mark here is the one who created the whole thing. So anyway, I don't want to jump ahead of Mark. Why don't you introduce yourself to our friends here and then we can get jazzing out around CSS?

Mark Dalgleish (01:00):
First of all, that's cool about the angular thing. I had no idea about that. That's awesome. So as I said, I'm Mark Dalgleish, and I work in Melbourne, Australia at a company called Seek. But as Kent said, I'm most well-known for co-creating our CSS Modules and I've been active in the React space and CSS space for quite a while now. I'm still trying to come up with new ways to rewrite CSS. For some reason I can't let it go. Here I am today.

Kent C. Dodds (01:29):
Yeah, that's great. You've been working at Seek for a very long time. How long have you been there?

Mark Dalgleish (01:33):
I've been there for, let's see, I've got to count now, 2013 I joined. So, what's that now?

Kent C. Dodds (01:38):
Is that eight years now?

Mark Dalgleish (01:40):
Eight years, yeah.

Kent C. Dodds (01:40):
That is wild.

Mark Dalgleish (01:42):
Yeah, it goes fast.

Kent C. Dodds (01:43):
I mean, if you're talking to my dad who's an accountant, he's like, "Yeah, you're just getting started, young buck." But in the tech world, eight years is a long time. That's impressive.

Mark Dalgleish (01:55):
Well, I get the space to do this kind of work, and that makes me happy. So, I'm not in a hurry to go somewhere else anytime soon.

Kent C. Dodds (02:05):
Yeah, I'm sure there are plenty of people who would like you to be in a hurry to go somewhere else. But yeah, that's awesome. You have done really cool things. So we're going to talk about this thing that you've built called Vanilla Extract, but you've done a lot of other things. I mean, CSS Modules came out of Seek as well, right? That was work you were doing at Seek?

Mark Dalgleish (02:24):
Yeah. So, we were pretty early on React at the time, for the server rendering, was really what got us interested in it. We were big on components immediately as React kind of trains you to be, really. We were scoping all our CSS to our components, but we were doing it manually with BEM name spacing. Then Webpack introduced opt-in local scoping, where it was like a special syntax to locally scope of class. I made a post-CSS plugin to just do that for every class automatically, which effectively became CSS Modules.
So, I worked with Tobias Coppers who created Webpack to basically make that official. I suggested it have a name and not just be a feature in Webpack, be a first class concept. We've since seen why that paid off because now it's implemented everywhere, even outside of Webpack, which is really cool.

Kent C. Dodds (03:19):
Yeah, CSS Modules was huge. I loved using CSS Modules. It just helped me immensely in my angular JS project, and eventually I wandered around in CSS and JS land. Now, I'm kind of hanging out with tailwind, loving that. But yeah, it's been kind of a fun journey with CSS. You mentioned earlier that you're always fussing around with CSS and trying to do things in different ways. Why can't we just land on something? Why wasn't BEM good enough? Why do we keep on changing stuff?

Mark Dalgleish (03:54):
It's a good question. Off the top of my head, I would say it's because it's really hard to manage at scale, and it always feels like we're never quite there. There's always some other problem. I mean, it's like anything in tech really. You never feel you've 100% solved something. There's always something not quite there.
I think with CSS in particular, what's pushed us to keep going is the move into design systems, and having CSS be part of a big component system that is operating at scale. Then consumers of those components may also want to write their own custom styles based on the primitives that are in the system.
Then another layer on top of that that's more recent for us is TypeScript. So, now you've got this whole angle of, well, I want type safety through all of this as well, and that completely makes you rethink, what are we doing with CSS? It's so dynamic compared to our React code if it's in TypeScript, that how do I join the dots on that one?

Kent C. Dodds (04:56):
Oh yeah, totally. Well, and you talk about design systems, that's another thing that you do at Seek. Is that your main thing is you're in charge of the design system, and that's kind of where these libraries and technologies come out of?

Mark Dalgleish (05:09):
Yeah, so on our front end, we're called the front end practices team and we look after all the shared front end tooling. So, that includes the design system, but we've also got build tooling and so on and vanilla extract now is part of that as well.

Kent C. Dodds (05:23):
Yeah, that's very similar to what I was doing right before I ended PayPal. So, I know that lots of the things that you were going through or thinking about, it sounds like you've been doing that for a really long time though. You probably have some really awesome experience. Do you want to just link drop the Seek design system? Because that's open source. I know that I've borrowed stuff from that.

Mark Dalgleish (05:45):
Yeah, I mean, that's one thing that we've really pushed for is even when the code's not designed for public consumption, like our design system, it's not for other people to use really. I mean, obviously you can use it if you really want to. But it's not designed for that.
I think its strength is that it's not trying to make everyone in the world happy. Its strength is that it's purely for Seek, and that's it. It means we can say no to lots of things and make it only do the things we want it to do. We can make it flexible internally if we want, so we still design to have a flexible system. It's just that, that flexibility, it shouldn't necessarily be at the public API.

Kent C. Dodds (06:23):
Yeah, absolutely. I think that makes tons of sense. I was just looking at your GitHub repo or org for Seek OSS, and you have 98 repos in there. So, Seek is way into open source, which is super cool. The one I was looking for is the Playroom thing that you've got in here, which I'd love for you to describe ... I know that we're not quite getting into the CSS stuff exactly. But this is just one thing I wanted to mention really quick. Can you tell us what Playroom is all about?

Mark Dalgleish (06:55):
Yeah. The Playroom is an in-browser JSX, I call it a design tool. I don't know, that throws people off. But basically, it's closest to something like a code sandbox, but I would say it's key difference from something like code sandbox is it's trying to be more approachable for non-developers. Both in terms of being able to rate the code first and foremost ... Because at the moment at the bottom of the screen, there's a code area and you write just JSX. You don't write a React component. You don't write a JavaScript file. You write just JSX. Internally we wrap that in everything it needs in order to render. As you type it renders into the I-frames at the top of the screen.
What's cool as well for us, because we have a theme system, is you have multiple frames visible, you can customize the width of those and you can customize the themes. So it lets you write JSX and see what it looks like responsively across multiple themes at the same time.
Because it's just JSX, you can sit with a designer or send a link to a designer and it is actually approachable because those component APIs, we designed them to be as human readable as possible. We designed them to use design terminology rather than just our own made-up terms. We try to make sure that we align with designers.
So, it ends up being this really nice tool for designing in the browser, communicating between designers and developers, showing examples of what our system can do. Internally, as maintainers of a design system, we use it as a way to kind of test out what the user experience of our components is.
You get some ways towards this with something like Storybook, I suppose. But the difference here is it's trying to simulate the design process, rather than I'm not creating a bunch of canned examples. I actually want to see, can I go from a blank page to a full UI quickly, easily? Does the code make sense? That sort of thing. So, it's a really tool for bringing all of these different things together.

Kent C. Dodds (08:58):
Yeah, so you can bring in some of your layout components. And then here's a button here, and a card and whatever else, all within the JSX, and then hand that off to the developer who wires up logic and stuff, right?

Mark Dalgleish (09:11):
Yeah, and a key thing there is you don't get to write a style sheet. I mean, we're talking about CSS today. The tool really pushes you towards having a complete component library. Because you mentioned layout. We didn't have layout components at the beginning and that stuck out.
Playroom helped surface that because I want to build up a UI, but I feel like I have to put these low level, in our case, a box component. I have to put these box components everywhere, and my UI is just box, box, box. our mentality was, if I'm doing like a high level UI, and I'm having to reach for these perimeters, we've missed something. We might not know what it is yet, but there's something missing here.

Kent C. Dodds (09:54):
Yeah, that makes a lot of sense. I would encourage people to go take a look at the braid design system because there are a lot of interesting things. There's the stack component and different things, especially with the layout stuff.
Actually my next question is then, if you have all of these layout components, haven't you then solved all CSS problems that your teams are going to have? Why do you need a library that your teams are going to be using, or open source something that people can use, if you can just encapsulate it all in a design system?

Mark Dalgleish (10:28):
So, the way I think about this is, this is your North Star, that I should never have to write CSS. In a perfect world, I pull in a component library, all the components are there to look and feel like all the standard patterns of my brand or whatever it happens to be, and I should just be able to compose those up and my UI is done. That's perfect world.
In reality of course, it's never quite that perfect. There's always going to be, like in this particular product, on this particular page, there's some very niche thing we need to do. Maybe it requires something a bit more tricky as well. There's some responsive style that is very particular, like we would not have created this concept ahead of time. It's very particular.

Kent C. Dodds (11:09):
Yeah, and you wouldn't want to include it in a design system either. It's too one offish.

Mark Dalgleish (11:15):
Yeah, that's right. To me, a big part of having a design system is being able to recognize those things and say, it doesn't belong in the core. That's just a custom thing you need to build, and that's fine. But we want to make sure that when you drop down a level to write custom styles, we have good APIs for that as well, hopefully.

Kent C. Dodds (11:31):
Yeah, absolutely. That makes a lot of sense. So, you're never going to be able to get away with not having one-off styles, and so you need to have a nice way to accomplish that. That's kind of where I guess CSS Modules came from. It was a really nice way to accomplish that.
Vanilla Extract is a lot more like CSS Modules than it is CSS and JS. Although you do kind of refer to it as CSS and TypeScript, which I think is fun. Seek, it sounds like kind of skipped over the CSS and JS craze. Why would you say that is? What made you decide that you didn't want to bring in something like Emotion or Glamorous for that matter for doing a CSS in JS in your products?

Mark Dalgleish (12:18):
Well, I mean, the first thing to call out is I've always been a fan of CSS and JS from the beginning. I was playing around with Radium and JSS in the early days, Aphrodite. I even helped design the Glamorous logo, I don't know if you remember that.

Kent C. Dodds (12:35):
Yeah, I do.

Mark Dalgleish (12:36):
Yeah, I also wrote a very popular article called The Unified Styling Language, and converted that into a talk where I was trying to sell CSS devs on the idea of CSS and JS.

Kent C. Dodds (12:46):
I [crosstalk 00:12:47] post a lot.

Mark Dalgleish (12:48):
Yeah, exactly. So, I've always been open to the idea of using different languages to describe CSS, first and foremost. I've always sort of felt like it seems like the future to me, the idea of having your styles written in the same language as your application, whether it's JavaScript or something else. The idea that you should have, I mean that's where the title came from, a unified styling language. You just have one language for your app and it can compile to different things.
So, I've always been in favor of that. A lot of it is just the particulars of where I happen to be. Because I'm at a big company that bet on CSS Modules early, but we scaled that up through components, I think, is the key thing. We treated components as our main public API and style sheets are almost like, hopefully you don't have to write too many of these.
So, we were sort of biased towards make components the nice part of our API and don't worry too much about how powerful your style sheet layer is. As we scaled that up further, I think it's almost like the further we went down that road, the harder it would be to, to convince us, like you should throw all of this away and move to something a lot more dynamic and powerful. Cause we actually felt like we didn't even really need it. We were getting away without it pretty well.

Kent C. Dodds (14:09):
Yeah. So, just kind of hard to convince yourselves that it was worth the extra runtime and everything else when you didn't have a severe problem with CSS Modules?

Mark Dalgleish (14:19):
Yeah. I mean, don't get me wrong, it would clearly be better from a developer experience perspective and that's definitely the trade off that we were kind of making there. It felt almost like it would be selfish for us to flip to something like that. Because what we had was working okay. We didn't have a big pain point in this area.
If we were struggling with it, then I think it's maybe worth taking a hit on bundle size, performance, those sorts of things, to make your development experience easier. But we just went feeling a pain point in that area. Until maybe a bit later. I guess that's where we jump a bit forward, where I think what broke our model was where we started to move into theming. We were in pre-CSS variables days where we just couldn't support them. I think they may have existed in those early days, but the browser support obviously was not there.
So, that's something where CSS and JS has always kind of been ahead, is that they can poly fill those sorts of features very easily. Whereas if you're working in static CSS, it's very tricky to introduce theming after the fact.

Kent C. Dodds (15:24):
Absolutely. Yeah, that's what I was going to ask you is, what would have been the biggest benefit for you moving over to something like Emotion or styles components or something? It sounds like, I guess, the biggest difference between ... Let me put this to you as a question. What in your mind is the biggest compelling reason to use a CSS and JS library?

Mark Dalgleish (15:52):
It's hard to pick. For me, the most compelling reason above everything else, and there's lots of good reasons, but the most compelling reason for me is, like I've referred to before and the title of my blog posts, this idea of having a unified language for everything.
If you're building a design system, let's say, you want to build up your design tokens, and you want to create styles from them, but you also want to use them at runtime maybe for some layout calculations or whatever it happens to be, I love this idea that I don't have to switch between these different languages and these different modes.
I actually liken it to what we saw with the introduction of node, where suddenly it was like, okay, I can have the same language across backend and front end. There's not this sort of arbitrary split in language anymore. I can create a single file, I can write a function and I can use that function on the server. I can use that function on the client, I actually don't care anymore.
I think that's why I've always been interested in CSS and JS because it's doing the same thing for styles. I can write my tokens, my logic, whatever it happens to be, and I'm not restricted on where this code runs. I think it just streamlines things. It means I can write unit tests for my styling logic in a way that if I was using SAS, I would struggle to do that. I mean, I don't even know. Can you write unit tests in SAS?

Kent C. Dodds (17:16):
It's possible.

Mark Dalgleish (17:20):
Yeah, and I think TypeScript to me is the biggest proof of why this is a good bet. Because if you bet on the JS ecosystem, that thing just keeps going up and up and up. If you've been writing in your styles in JavaScript and TypeScript comes along, suddenly you're writing your styles in a type safe language, and your editor is telling you that you're getting your styles wrong when passing them around.
When you're writing reusable functions and things like that, that are operating on styles you've got a type checker at your disposal now. That's something that when we were back in CSS Modules days, where at Seek we were using Less, because that's just what we'd used since forever.
The deeper I went into that world of writing real, design system level, reusable mix-ins and so on, it was getting to the point where I could barely read the code I was writing, and it was really heavy duty. I just felt like I was in a whole different environment compared to when I was in the JS world. I felt a lot better supported on the JS side when it came to really complex code.
If I was writing code like that in JS, what would happen is I'd go, "Okay, obviously I need to unit test this thing if I'm struggling this hard, and I need to test drive it." Because you write the code, it doesn't work. You tweak it, still not working. You're just not getting it and you're like, I need to take a step back and work through it.
The tooling in the JS space for dealing with those sorts of problems is so mature. To me, that's really the benefit is just bringing a little up together and saying, it'll compile to CSS. It doesn't mean I need to author it in that language. We have different constructs for that in the JS space and that's actually more ergonomic to me as a developer to not have to jump across these language divides.

Kent C. Dodds (19:12):
Yeah, absolutely. That makes total sense. You mentioned when you've got a complex function that's dealing with CSS and having the TypeScript stuff in there to help with that, instantly we have to remember that by putting our CSS in JavaScript, we have the ability to make those functions.
Whereas you have mix-ins and stuff, but having a JavaScript or TypeScript as something that actually executes and runs and you can debug and stuff, there's just so much benefit to that. But there are a lot of trade-offs there, too.
So, with Vanilla Extract, would you say that's kind of a marriage between CSS Modules and CSS and JS? Is that kind of what am I understanding what Vanilla Extract really is correctly?

Mark Dalgleish (20:05):
Yeah, it's trying to get the best of both worlds. There's always going to be a trade-off here. So, one thing I want to be clear on, upfront, is that I'm not pitching this library as the solution to all CSS problems, and all CSS and JS should switch to this. But I think if you agree with the philosophy, then you should definitely use it. So it's a question of what, what do you think about that? The trade-offs here?
So, I mentioned before about struggling with really complex pre-processor code, and feeling like, I just want to write this in a general purpose language that has better tooling around it. So, one thing I did pretty early on in our journey, staying in static CSS land, was can I at least use JavaScript to create my CSS, even if it's static?
So, what I found was, I actually did some early experiments in this space. I've made a Webpack loader that turned JSS code into static CSS. It was more of a toy. I didn't end up using it. But at Seek, what I did is I introduced this Webpack loader that I found called CSS in JS loader. It let you basically use JavaScript as a pre-processor, and you'd come up with a file extension, like .CSS, .JS, and you'd target that with Webpack.
Then what would happen is that code would get eval-ed at build time, and the exports of that file was just effectively a JSON version of a style sheet. It would look exactly like a style sheet, just written the way you would have to write it as JSON. So, that meant that you had the full power of JavaScript to build up that style sheet.
To me, that went a long way in fixing the biggest problem I had with dealing with pre processes, while keeping the runtime characteristics. There's zero runtime in that world. It's all written in JavaScript. But we're talking about TypeScript. The problem with that model was that it basically breaks TypeScript because if you actually look at what's being exported from one file, which is a big JSON blob of a style sheet, and then you look at what's being imported on the other side, it's like what you get from a CSS module.
It's like a styles object with the locally scoped classes. The two actually don't match up, so when you point TypeScript at this, if you try and give it those two things to TypeScript, Typescript's like, "This doesn't make any sense. What you're exporting, what you're importing, they're different types." That's what forced our hand to have to sort of go back to the drawing board a bit on this whole ... We liked the idea of writing in TypeScript and then running it at build time and exporting the built styles, but we had to sort of rework it so that it was actually type safe.
I mean, I don't want to go through the whole journey here, we don't have a huge amount of time, but Vanilla Extract was about saying, okay, now that CSS is a lot more powerful, we have CSS variables, we want to locally scope, not just our classes, but we want to locally scope our variables and export those across the boundary.
CSS Modules only exports your class names. We want to export everything that's locally scoped, including your variables. Then that way we have that type safe boundary between the static CSS and the runtime code, but we also have the ability to interact with CSS variables, which sort of reintroduces a lot of that power that maybe we were missing in the old days with static CSS.

Kent C. Dodds (23:31):
Yeah. It sounds like CSS variables or custom properties, the lack of that feature was what drove a lot of people to CSS and JS, is because their hands were tied, especially with theming, that was a big challenge. So, lacking that amount of power, we really wanted to go with CSS and JS. That solves a lot of problems and many problems that most people don't have.
But it just happens to solve all of those extra problems because it's a runtime. But then you're paying a relatively significant cost, and so if you only need a few of those benefits, and then CSS custom properties comes around and you don't need those benefits anymore because that's built into the browser, now maybe we can take a step back and think, okay, based on what we have offered to us by the platform, what do we need on top of that? In your mind for your use cases, Vanilla Extract kind of gives you everything that you need for a typical web application without the runtime, right?

Mark Dalgleish (24:45):
Yeah. So, what you're saying is right to me, with the CSS variable angle, where it's really forcing us to sort of rethink what do we actually need now that the platform is a lot more powerful in this space than it used to be? So, what we're trying to solve, I guess, is I'm seeing that we're re-introducing some of the problems that we solved.
So, you talk about CSS Modules being so important. It's because for a lot of people, it introduced this idea of locally scoping typically global things in your style sheet. I guess it does two things, one is, of course it means that you no longer need to worry about naming things in the global scope. That's nice, you don't have name clashes.
But in my mind, the real benefit on top of that is the fact that it forces you to make your dependencies explicit between files. This React component needs this class name from this file, and it has to actually explicitly ask for it. It doesn't just sort of get it for free from the ether.
My concern is that, I'm seeing that people are rightly recognizing that a lot of this power that's in the runtime, we can move it into CSS variables. I think they're right. The problem is I think that we're, re-introducing this global scope again with CSS custom properties. Because what someone will do is they'll write a React component that uses Emotion, let's say, and then what they want to do is stop using the theming system Because they want to say, "Let's do the theming in custom CSS properties. It makes perfect sense to me."
The problem is what they'll do is they'll just start, in my mind, just hacking global tokens as variable names. So, if you look at it through that lens, what you have is a React component that depends on a brand color variable. Where did that come from? Nothing in the code says, where does this come? Which file created that variable? Does it even exist? Maybe I've got a typo and it's actually spelled color with a U because I'm in Australia. Who knows? My builder won't tell me anything's wrong, my editor won't tell me anything's wrong. It's only when I run the code that, "Oh, there's no such variable. Whoops, I didn't realize." So, in trying to take a step forward, we've actually taken a big step back as well if we're not careful.
So, for me, like, what I'm trying to do is, I feel like we're pretty early on that journey, actually, of like going back to CSUs variables. So, I'm trying to catch it early and say if we're going to use CSS variables at scale, which is what's going to happen, we need to make sure that we don't lose the benefits that we've introduced in these other areas with scoped classes. We want scoped variables as well. So, if you want to use that brand color variable, you have to import it from the thing that created it.
Especially in the world of TypeScript, that's really useful that if I get the name wrong or whatever it happens to be, my editor will tell me that variable does not exist. It's been deleted, it's been renamed, whatever it happens to be, and so now my CSS variable code can scale as well as my prior CSS code.
The thing is, I feel like the tooling is quite early in the space. I'm not sure who else is doing local scoping of first-class CSS variables. There's lots of tools out there that create CSS variables behind the scenes, and kind of try to abstract it away from you. But we're giving you first-class. You know you're creating CSS variables, you just have a reference to them that you then can pass around your style sheets.
Because in JavaScript, you can export them over the bridge to the runtime, so now your runtime if it wants to can get and set those CSS variables on individual elements. So, you get that power, but you're avoiding that global scope as well.

Kent C. Dodds (28:28):
Yeah, and I think that's really useful, especially being able to import those. I wrote a blog post, what did I call it? Use CSS Variables Instead of React Context, now that we have CSS variables.
In that, I'm describing, well, what if you get the CSS variable wrong? I demonstrate how you can put those CSS variable names, and have them be generated through your TypeScript. But in mine, you have to duplicate what you have in your CSS as you're defining your CSS variables, and then duplicate that in your TypeScript. So, you just have a mapping between those two that you manually keep up to date.
But Vanilla Extract, it does that automatically. We just have a little bit of time left, but I'd like to get some idea of what Vanilla Extract is, for people listening. So, how does it accomplish this without any runtime?

Mark Dalgleish (29:28):
Yeah. So, it's built on the assumption that you're using a bundler of some sort. The idea is that, let's say you have a React component and it wants to input some styles. What you do is you import from a special fall extension. I kind of touched on it earlier. Our convention is you name your file .CSS.ts, and then you have this Vanilla Extract plugin into your bundler. So, we have support currently for Webpack and for ES build as well.
So, what happens is the bundler notices that you've inputted this special file, so instead of just treating it like a regular file, it spins up a separate compilation of that one file and everything it depends on, and then it evals it. So, inside of that file, you import from Vanilla Extract/CSS, so you import the style function. There's a bunch of other ones. There's functions for creating themes and different variants of themes and so on.
So, you have the full power of CSS, you just have to call functions to create your styles. Behind the scenes, we basically just catch everything that you define while evaling that file and we create static CSS files from it. What we do is, so everything that you export gets put in the resulting file that is there at runtime.
So, it's similar to CSS Modules in that there's an object, like a JSON object, of everything you exported. So, all of your class names, all of your variable names. That's the difference with CSS variables is you have to explicitly export everything you want to access. But that's normal for JavaScript.
So, what's interesting here is you've kind of got the best of both worlds in the system, where your app's all built in TypeScript, let's say. Your run time code, your style sheet code, it's all TypeScript. You're creating styles and exporting them to the runtime. It all just kind of makes sense on disk, and you have variables. So, you've got dynamic stuff. You've got theming. We have APIs for changing the variables at runtime in a top safe way.
So it means that you've effectively made, the way I think about it is, it's almost like a pre-processor where, you might have a SAS file next to your React component. The difference here is you've got a .CSS.ts file. So, you end up having a shared language between them and you can do a lot more things in terms of you actually export any data structure you want from the style sheet to your runtime.
But it has the same performance characteristics of something like SAS, where it all just runs at build time, static CSS comes out the other end, and at runtime there's really no work left to do. It's just looking up the pre-built classes that you've created.

Kent C. Dodds (32:16):
Yeah, very cool. Because it's built into the bundler, you get code splitting for free and stuff too, right?

Mark Dalgleish (32:23):
Yeah, exactly. I mean, we do things like bundle split to themes. So, for our use case we have a more advanced theming API where you can create a theme contract, and then you can put that in its own file, and then you can have a bunch of separate things that it'll import that contract and implement it. They can be their own files. So, then when you're building for production, you can make it so that we only load the theme that you actually use, because it's a different brand or what it happens to be.
So, it just feels like normal code you would write in a bundler, but it's old static CSS out the other end. So, it's really trying to get the best of these two approaches in the one setup.

Kent C. Dodds (33:06):
Yeah, absolutely. For me, with CSS in JS, one of the nice things that I really liked was being able to just do things in the same file, which of course you wouldn't be able to do in here. I think I can get over that.
But one of the interesting things was moving from CSS in JS to Tailwind, where I kind of started to feel like Tailwind actually felt very similar to CSS and JS. Because with CSS and JS, you have just so much power. You're using all of JavaScript.
But as I started playing around with Tailwind, I realized I didn't need that much power. All I really needed was a constrained set of atomic values that I could apply, and then, depending on the state of my component, I would apply different classes. It seems like this plays really well into that same idea of kind of atomic CSS as well.

Mark Dalgleish (34:05):
Yeah. Well, it's funny you mention it. We're actually actively right now working on a library on top of Vanilla Extract, which who knows, maybe by the time this comes out it'll actually be available. Because that's how we use Vanilla Extract at Seek. I mean, when I say use it, we're currently only in a branch of Braid. We don't have it in production yet.
But our prior work works this way, where we have a core set of reusable styles, like the way Tailwind works, where the idea is that should cover 80% of your styles. In a lot of cases in it, within our design system, we don't have to write a style sheet for a component.
We almost use the fact that we have to write a style sheet as almost a note that, okay, maybe we've missed something in the core. We try to reach for the common styles first. I mean, to me, that's what the utility first and styling mindset is about, is about saying, can I do it with this constraint set, if I can?
Because in CSS, there's a bunch of ways to do the same thing. It kind of guides you towards, try not to do it a million different ways. Try to use the core set of reasonable things. Of course, if you have to, you can go build custom styles, but it just guides you away from that, which inherently kind of makes you think about the size of your final CSS bundle. Because the other approach would be, write all the styles you want and we'll try and atomize it after the fact. That works too, but the problem with that is it forces you to almost not care about unifying your approach on a core set of styles.
So, you talked about the pain of having a separate file, and I definitely hear that. The benefit of our approach being a separate file that we eval in its entirety is that it actually opens the door for people to write obstructions on top. Because as a point of contrast, the other way you could do static extraction is you use a static analyzer of some sort to look for certain patterns in the code and say, "Okay, that bit looks like a style. Okay, we'll try and like do some magic to turn that into a class."
The problem with that approach is it kind of prevents you from building abstractions on top. Because if I wrap that thing in a function that takes arguments, that there's a style call from some third party library. If I try and wrap that in some higher level thing to generate atomic classes let's say, I actually can't do that because now the static analyzers can't see any style nodes anymore. All it sees is my abstraction.
We don't have this problem in Vanilla Extract because the file boundary is what says, "This is all style. Everything from this file onwards is style code." So, you could technically not even import an API from Vanilla Extract. I could input Kent C. Dodds' atomic utility library, and just run that, and it will all still work because some file that you input create styles, and it just gets caught when evaling the whole thing.
So, that's what opens the door for us to create these libraries that say, "Okay, give us some config. We'll give you that atomic set of styles that will cover your 80% case. We'll even hopefully give you APIs for quickly wiring it up to a component as well," so you can get your box component or whatever you want to call it.
Then you're starting to get to a place where it's like, "Okay, sure, I have to create separate style sheets for my components or whatever," but ideally I'm not even doing that half the time. Half the time, I'm just using my core 80% of utilities over and over again.

Kent C. Dodds (37:32):
Yeah, yeah. Makes a lot of sense. Well, I could probably talk with you for another half hour, but we are past our time. So, I'm just going to wrap things up here. So, was there anything else that we didn't talk about that you wanted to make sure we touch on?

Mark Dalgleish (37:50):
I think that'll do it. You can follow me on Twitter if you want to hear more.

Kent C. Dodds (37:54):
Great, and I do recommend that. So, we'll have a link to Mark's Twitter handle in the show notes. For our homework for today, we want you to read the blog post that I referenced, Using CSS Variables Instead of React Context. Because it kind of gives you an idea about the CSS variables and that maybe we don't need to use JavaScript for some of the dynamics stuff that we can do now.
Also, to check out Vanilla Extract, because interesting and innovating things going on there. It's actually a great time to get involved in this because there's a lot to be done to make this better. Anything to add on that, Mark?

Mark Dalgleish (38:31):
Yeah, I would love to hear what people think about this. If this is something that you want to try out in your projects, I would love to hear how it goes for you or any thoughts you have. Because we're pretty early. We're pretty open to the community here, and we're doing things quite differently. So, I'm always looking out to hear what people think about it. So, please reach out to me, let me know how you go with it.

Kent C. Dodds (38:58):
Awesome, sounds good. Hey, thanks so much, Mark, for this. This has been just a pleasure. Thanks everybody for listening, and we'll see you all later.

Sweet episode right?

You will love this one too.

See all episodes

Featured episode

Jhey Tompkins Chats About Building Awesome Demos

Season 4 Episode 24 — 34:07
Jhey Tompkins