Brian: PodRocket is sponsored by LogRocket, a front end monitoring and product analytics solution. Don't know what that is, go to logrocket.com. Thanks. Ben: Hello and welcome to PodRocket today. I'm here with Mark Dalgleish, who's the creator of the vanilla-extract, a really cool CSS tool. And Mark, you also created CSS modules as well, right? Mark Dalgleish: Yeah. Well, first of all, I have to say co-created, it's always a bit of a team effort. That's a yes. Yes. I've had a big involvement in both of those technologies. Ben: So maybe we start with just a quick primer to CSS modules because I think it's kind of foundational to an extent to vanilla-extract and it seems like vanilla-extract kind of builds on that work, but CSS modules, I used it a long time ago, but I don't remember entirely. So maybe you could give us and for folks who haven't used it before, you could give a quick primer to kind of the problem, the CSS module solves and how you use it. Mark Dalgleish: Yeah. Sure. So I mean, people that have been working in the CSS space for a long time know that it's really hard to scale CSS and jumping forward a bit, there's been a big rise in component systems. So people trying to figure out how do we scale UI just generally not just CSS. And then you have this question of, well, how does CSS fit into a component system? And it seemed to me like the best answer to that question was the BEM methodology, block element modifier, which when it comes to CSS, it's effectively just a naming convention to say this piece of CSS belongs to this part of the UI so we're going to prefix it. If it's a button, let's say belongs to a button, we'll put button at the start of every class name and then a couple of underscores. Mark Dalgleish: And then that gives you scoping effectively. It says this CSS belongs to this component. The problem with that, I guess at scale is it's really just a convention. So you need to first of all make sure everyone knows to follow this convention. Or maybe you have some linting rules that, that I've seen people do this where they'll say if the class names in this file did not start with the file name or whatever it is, then it will be an error. So there's ways you can kind of do it manually. CSS modules is effectively saying, we believe in that philosophy so much that it should just be the way CSS works effectively that if I write a class in this file, it is locally scoped to that file and effectively becomes like an export from that file. So then the other side of the equation is okay, how do you actually enforce that? Mark Dalgleish: So instead of writing button at the side of all of my class names, I can leave that out. How do we make sure that there is that mapping of the styles to the file name and the way that it works is on the other side, right? Like, so in the component system, you're going to have a JavaScript file that, well, if you're in a JavaScript UI context, that's where we've been working. So something like React to it was what we were working with. You've got your JavaScript, React component. And it had a dependency on the CSS file. So when we were doing it manually, we were using Webpack, which is a module bundler. Its lets you declare these relationships. So you can say my component, button.js Depends on button.css to work. It's a strong dependency there, where I like, if the CSS doesn't come along for the ride, this component is not going to work. It's going to be broken. So what's cool about Webpack is it lets you say at the top of your file, import the CSS file. Mark Dalgleish: What we would do with CSS modules instead was basically say like, you actually have to input the class names from the file because the class names are going to be hash like gobbled. Like it's not something you would type by hand, you have to explicitly get the reference to the class name. And so what's cool about that is when you run all these things together, you have to import the class names that you're going to use and they're not human readable. You're forced to import them. You can't sort of opt out and type it manually. You have to import it. It means that you get much higher maintainability on your code because now it's not a convention you have to follow, it's enforced by the technology itself. Mark Dalgleish: And when you operating at scale, especially, when you're talking about companies where there's a lot of mixed skillsets, not everyone's a CSS expert, these sorts of things really, really helped because now CSS just works in a maintainable way by default and you don't have to sort of remember to do it. And I think that's why we saw so much popularity with CSS modules because it just made CSS kind of work in a better way. But otherwise it just felt like CSS to people. It didn't feel like this radically different technology. Ben: Got it. And so correct me if I'm wrong, but with CSS modules, you're always writing your CSS as CSS, right? It's not kind of what has now become kind of the norm, I guess, which is to write CSS-in-JS or CSS-in-TypeScript, which I guess we're going to talk about soon. So you write vanilla CSS or I guess can you do like Sass or SCSS with CSS modules, is that compatible? Mark Dalgleish: Yeah. So that's one of the big advantages of that approach, is it really slots in, well with the rest of the CSS ecosystem because tools like Webpack, they let you chain loaders together and you can say, I want to run it through Sass loader before it goes through CSS loader with CSS modules enabled. And you can plug post CSS in there and get Autoprefixer or whatever it is. And so I think that's why it hits that sweet spot between the two ecosystems, because you might be into React and that sort of thing, but you still might be into the broader CSS ecosystem and that the two connect really well in that regard. And so it felt like a very in that way, it's like the safest choice because you're not kind of leaving one ecosystem for another, you get to bring the two together. Ben: So I guess the question then is like, what are the downsides to CSS modules that will guide you kind of down the path of building something new? Mark Dalgleish: Yeah. So we started a design system where I work at SEEK, like it was actually our second take at a design system because it needed to be themeable. And what I was really keen on was this idea of like trying to hang on to CSS modules and the fact that this is a zero runtime cost because we were already invested in that technology at that scale and the way we was kind of doing it was effectively like if you think of the way Tailwind works, it's the easiest point of comparison for me is you've got all these low level classes that are based on some design rules that you've set up in the context of Tailwind, it'd be in your conflict. Like you've said, here's my spice scale, here are my colors and so on. Mark Dalgleish: That's effectively your theme. What we did is we kind of set it up so that CSS modules would create a theme and we could swap out a collection of low level classes that were a CSS module. And that was like your thing. But then I guess the thing is like we were taking CSS modules to the absolute extreme in terms of trying to make it themeable. The key thing though is I should say this was quite a while ago where we needed to support i11, So we couldn't use CSS variables, you might be thinking, why not just do CSS variables? So this predated that. And so as a team, we created this solution called Treat, which is like the precursor to vanilla-extract and that was more coupled to Webpack. And it let us effectively write our styles in TypeScript, but generate multiple sets of styles. And I guess the reason we went down this road is that like we were feeling like in the world of components, the boundaries between your CSS and your JavaScript start to break down, that's maybe the controversy of it, right? Mark Dalgleish: Some people really don't like these boundaries coming down, but to me, it makes a lot of sense that, you still have this separation of CSS and JS and HTML at the component level, but they kind of need to talk to each other and then you can pose up in a high level of the component layer. And what we found is that for one thing that the context switch of going between languages was really difficult. Like if you think about what's really great about node, right from a JavaScript developers perspective is you can jump between these radically different domains front end, back end. And you're just sharing code between them utilities, data, whatever it is. And there's not this feeling of radically different worlds. Like what really liked about working in JavaScript or TypeScript in that case was that we could share design tokens easily between the CSS and JavaScript. We could write logic very quickly and easily that iterates over those tokens and output CSS and not feel like it's just this complete context switch. We'd done similar things before in less. Mark Dalgleish: And I personally, I found like it was much harder for me to work with than JavaScript and not due to lack of experience. I just found like, especially as we moved into TypeScript, like it's just a much nicer, I find much nicer language to work with. And so that's one big advantage. And the second part of it is I've touched on it briefly is the type safety. So I've never been big on type safety from a purist standpoint. I've always looked at it from a pragmatic point of view. And what brought me to TypeScript was working with design systems and creating design systems that other teams then have to consume. Having that boundary be tight checked is very, very valuable because if we ship a breaking change to other design system. When our system was in JavaScript, which it was, earlier on, if we shipped a breaking change to an API, consumers would only know about it by reading the release notes very carefully and making sure they've read every point. Mark Dalgleish: And if there's something that broke, they had to make sure they read it, understood it. If there's a migration guide, they have to meticulously follow the guide. And if they didn't, something will break. And that was what got me into the world of top safety was like, okay, it makes so much more sense that we can ship in updates, still have the release notes and everything, you still do that, but it means that if they don't update their code to match the new version, like their project won't build and it'll pinpoint, this exact component like that props, not a thing anymore. You need to update that. And it's really hard to argue with that. People debate JavaScript versus TypeScript, I find it's kind of impossible to ignore at scale the benefits of that. And so I came into it with that head space, but like, what's interesting is I feel like once you get bitten with the bug of type safety like that, you find it just starts to spread everywhere. Mark Dalgleish: You're like, I want anything that's not type safe in my project, I suddenly feel like it's risky code. If I changed my style sheet and I don't update my UI code. In any of these relationships, you want them to be top checked. And that was really pushing us towards getting our style sheets to be written in TypeScript as well. So that, let's say we update our design tokens in a central place that's consumed by our runtime like view code. And also by our style sheets, like both of those parts of our code base will be telling us, Hey, you're referencing design tokens that don't exist anymore, or they've changed whatever it is. And so, if we were still working in Les, for example, we wouldn't have that benefit. And so that's what really started pushing us more and more towards having this unified top checked language where we can easily share across these boundaries and not feel like we're working... I'm trying to build a component, but I keep having a context, which are two radically different environments. Ben: And as I understand it with, with vanilla-extract, you kind of have these tools out there, like CSS modules and stuff, which are, you're shipping a dynamic CSS engine to the client with vanilla-extract, like CSS modules at build time, you generate static CSS. Correct? Mark Dalgleish: Yeah. That's the thing. While I'm definitely not against runtime, CSS and JS engines in the browser, I think they're very cool. And they can do things that we can't do by virtue of the fact that it's happening at runtime. Our experience was that, I think it's because we built up a system around CSS modules early, we had come up with other solutions to the problems of not having a runtime. And so to me, I mean, I keep referencing Tailwind, but I think it's the best open source example of this philosophy, which is, if you think about how something like Tailwind works, where you've got these low level atomic classes, you've got a class for padding-top large, padding-top medium or small, or that they'll have different terminology. Right. But you've got micro classes for each value, if you then think about, okay, I'm writing something like a React component that's dynamically switching out these classes, if you squint, like it kind of is like a runtime, CSS and JS engine in a way, right? Mark Dalgleish: Because you can have a prop on your component drive how much padding is on the left of this component. And that that's ultimately, I think in the vast majority of cases, that's what people are actually looking for in a runtime, CSS and JS system. They're trying to say, I just want to be able to say, based on this prop, change the background color, change the board, change the padding, change the whatever. And if you do that with traditional CSS, the way you typically write with classes, with a bunch of rules attached to it, that gets frustrating, because you're like, well, I kind of have all these different moving parts of my component. And I just want to make bits of it dynamic. The runtime CSS and JS solution is one answer to that. But the atomic CSS approach is another way to do it. Mark Dalgleish: And I find what's great about it, is it forces it has a separate benefit in my mind, which is it encourages you to follow standards as well, because you're saying, well, rather than just making the padding dynamic and calculating it on the fly, based on something like here's a pallet of paddings that we've sort of agreed upfront is our white spice scale, pick something from this and there's already a class for it. Like it's sort of the work's already been done. And so then you get the benefit of like, well, there's actually no runtime beyond the UI code, switching out the classes, you get the consistency of devs, aren't just making up padding values whenever they hit the need for some padding and it means that yeah, suddenly the runtime cost just drops to basically zero from a CSS perspective. And so that's kind of in our approach tries to say, what we want to do is generate as much sort of low level pallet based styles upfront. We bind that to a component as well. Mark Dalgleish: We have a box component, which is effectively like a component version of something like a Tailwind where it'll have a padding top prop on it. So you can say box padding equals small and it'll just pull up the class it's already been built. And this is where we like the TypeScript side of the style equation because we generate all of these styles in TypeScript based on objects that define the theme. And we find it's just very easy and natural for us to iterate over objects in TypeScript and the interfaces are all type checked and everything, and that flows through into the components. And so, yeah, for us, that's really what it's about is saying, how do we get at the same benefits of runtime CSS-in-JS without having the same costs and maybe in some ways helping solve other problems that it has, which is, if you can just write whatever styles you want, it tends to become a bit of a spaghetti mess over time. And we actually want to bring it down to like, here's a core set of styles we want to reuse. Ben: So taking a step back, kind of on the question of like writing CSS, CSS, or CSS-in-JS and CSS-in-TypeScript, like remember a number of years ago, five years ago, whenever the paradigm of CSS-in-JS was first coming out, one of the kind of criticisms of writing CSS and there's a couple of criticisms people had originally, like one is just like a lot of people, especially designers are often very fluent in CSS, maybe less so when you're writing CSS-inJS. There's a lot of editor tools built into VS code or sublime or whatnot that help you write CSS really quickly that don't quite understand that you are writing CSS and JS. There's designed tools that can spit out preform CSS often. So I'm curious, do some of those concerns still exist? Ben: And I remember when CSS modules came out, like it was awesome because you were writing CSS, but got a lot of the benefits of componentization and working, it worked well with React. So I'm curious, like kind of do those concerns still exist in 2021 has tooling caught up, have people gotten used to CSS-in-JS or TypeScript enough or kind of what's your thought on that? Mark Dalgleish: This is a really interesting question because there's definitely a tension here, I think, around the quality of the code base that you're working in versus its integration into other tools. It's a really tricky one. I should probably say, a lot yeah. Of what I'm saying is hinging on a certain philosophy, which I've touched on a little bit, which is going all in on components. And so my view is we're still working our way towards this. Right. But the goal for me of designing in code, that in and of itself is a goal to me. I want to be able to iterate on a product in code as much as possible. And there's obviously always going to be a place for more conceptual work or freeform exploration or whatever it is, but your sort of day-to-day work where you're like, I'm just designing a form in a card, with some buttons at the bottom it's a very standard thing. I don't really want to see work like that happening at a low level, in a design tool where you can kind of do anything or even in CSS where you can equally do anything. Mark Dalgleish: Ideally something like that in an established system, you're not even writing CSS at all. Why would I write CSS for things that are just run of the mill standard things on my site or my app. And so to me, where we're trying to head to is that we're trying to make component systems and design tools should be based around components. And I think that's the movement we're seeing is component based design tools. They don't actually care how your components are built. They can be built with vanilla extract or CSS modules or runtime things or Tailwind or whatever. They don't actually care. All they care about is that you have a set of components built on top that has a sensible design oriented API. And to me, that's what you're supposed to be giving to, in this new world we're heading into, this is what you hand to your designers. It's like, here are the Lego blocks that we've prepared. If there's anything missing, obviously we have a conversation and to me, that's the benefit of these design tools, is it actually gets designers and developers better aligned. Mark Dalgleish: I've never been a fan of like, here's a big blob of CSS to give to your developers, like problem solved. At least the developers I've worked with don't. We don't like that at all because it's like, well, we don't think about it that way. Like it's, we don't just copy and paste big blobs of CSS and go job done. We actually try to architect it properly. So as we've moved more and more towards component systems, and we might go into more detail, but we have our own component-based design tool, lets you write in JSX called playroom. We've been using that internally a bit. And we find like designers themselves who have gotten into this space, have said, "I actually find this makes handover," as much as I don't like that term, it makes handover much better with developers because now they're saying like "it's a stack of cards with this much space and inside there's a stack of text fields "or whatever. Mark Dalgleish: And they're using the same terminology as the developer. And then the developers can copy and paste that into their app. And it is actually at the level of obstruction that they would have written it themselves more or less. There's always going to be a, for a bit of clean up or maybe they'll say, okay, maybe they've written in a way I wouldn't have written it, but it's way closer to what the developer was going to write. Then like a big blob of CSS out of a tool like Zeplin, let's say in a component system, the developer was not going to write a bunch of low level CSS on some dibs. Like that's just not how they operate. And so to me that then that then changes the equation around what you're saying around, how much can I lean on traditional tools? Like develop the tools that let me just edit raw CSS directly, how does that fit into a component system? Mark Dalgleish: And so I think the tooling needs to shift to accommodate. So for example, you may, instead of using the CSS Inspector to play around with the design, you might want to actually use the React. If you're using React, obviously it could be different tools and in our case, it's React. If you could use the React dev tools to inspect the componentry and change the props, rather than the CSS, because in theory, that's the level of abstraction you're supposed to be designing at. Ben: And what is Sprinkles? I'm curious, Sprinkles and dessert-box. Everything is food themed here, I guess. But tell me about kind of those abstractions and how they fit into a vanilla-extract. Mark Dalgleish: Yeah. So I talked earlier about our philosophy of saying having these low level atomic classes that you can swap in and out, that is really just like an architectural opinion though, on top of whatever CSS engine you have underneath. So the separation is kind of like this, vanilla-extract is almost like your Sass and CSS modules in one, it's like a preprocessor where except TypeScript or JavaScript is your pre processor. And it outputs locally scoped classes. But beyond that, it's completely on you kind of what to do with it. Again, just like if you were using SASS, it's like, whatever architecture you use is that's on you. Sprinkles is our opinion of how to have low level atomic classes built on top of that system. So I keep using this comparison, but like you can think of Sprinkles as like a Tailwind light where it's like plugging your config into this library and it will spit out like a function which we call the Adam's function. Mark Dalgleish: And it's basically the equivalent of if you're, obviously you're assuming people understand what Tailwind is, but in Tailwind you write a string of classes, which is like, here's how much I want padding top of this. I want padding bottom of that, I want background of this. It's the same concept, but I mean, again, I said, we're big on type safety in our case, rather than being a long string. It's like an object where you'll say the padding is this. And the background is that. What's cool is that it's all type safe. So based on your config, if you say background is a sea green and that's not actually in your palette, it'll be like, sorry, type error. Like that's not one of your backgrounds. But so that what's cool about it is it ends up with the same thing effectively as Tailwind, which is you pass in an object with all of the low level style properties you want. You can't do silly things, things like Tailwind let you do where you could say, padding top is small and padding top is also large. It's like, well, hang on which one's going to win. Mark Dalgleish: In our case, because of the higher level interface on top, we can make all that safe, but then out the other end comes a big string of classes. So if you've said that the padding is small, you'll actually get a padding top class, a padding bottom class, padding left class, padding right class is a string coming out the other end. And that's the way we tend to write most of our styles in our system is we lean on this sprinkles. It's effectively like a framework. We lean on this framework for most of our styles. And you mentioned dessert-box. So it's actually like a third party library. We've rolled our own equivalent in our system, but the idea is basically like, I would actually want to take that and map it to a component. I mentioned before we have our box component. That's what the dessert-box is alluding to is the box component, because it's like, yeah, if you're in a component system, it's useful to have a component, which is just your low level element render effectively, which binds all of your CSS rules, like atomic CSS rules to a type safe component. Mark Dalgleish: So then like I said, you end up feeling like you have a runtime CSS and JS library because you can have a component that just dynamically swaps out all these styles, but it's all just mapping to this sprinkles based framework underneath which sits on top of vanilla-extract. So there's no runtime cost to any of this. Ben: So what's the future of vanilla-extract? Is the tool more or less complete or do you have things that you want to build out moving forward? Mark Dalgleish: Yeah. I mean, I think it's one of those things where it has a lot of potential, it depends on what people want to do with it. We've very much built up everything we need around it. What's cool about it to me is that like I've compared it to CSS modules, right? There's probably one thing I've sort of haven't touched on is how it's actually a lot more powerful than CSS modules in the sense that, okay, if we look at a CSS module and it looks like a CSS file, you write a bunch of classes in there. All of those classes are implicit exports. So if I write a class of .A, a class of .B and .C, when I go and import my styles from the JavaScript side, I've just got a single flat set of imports. Mark Dalgleish: I've got styles.A, styles.B, styles.C. And that's actually one of the things that we found difficult to work with CSS modules because if you want to do atomic styles where you've got like effectively within one file, you've got subsets of styles, like namespaces, like you might have your padding styles, you've got your margin styles, you got your backgrounds, your borders, whatever. You kind of want all of them to be isolated until like nested. You want to be able to say like styles dot background, dot whatever, and because that also helps with the type safety angle, because it's like, then you're limited to what are my backgrounds? What are my borders? And so on. That was one of the things that led us towards breaking away from CSS modules, because we wanted to have more fine grain control over exactly what we're exporting from our style sheet. We want to be able to create a bunch of styles that are out backgrounds and then go export constant background equals an object of styles. Mark Dalgleish: And what's interesting about that is it means that, that's actually what allows Sprinkles to work, because with Sprinkles, what you're doing is you're actually like creating like a data structure, which is like, everything you need to do that mapping at runtime, because it needs to know, what are your backgrounds? What are your borders and so on? And, and it needs to know like, what are my defaults? And things like that, does it have a default? What are the names of my break points? Or like all this data. So you with vanilla-extract, the way to think about it is you can export whatever JSON you want from a style sheet. And that's what allows you to build these higher level obstructions, even though you're still operating in that world of like, I have my style sheet, we still talk about style sheets. So even though it's in TypeScript, we still talk about this idea of like, I have my style sheet, it's all statically built at runtime. Mark Dalgleish: It's this really powerful mechanism that lets with the JSON exports that lets you kind of invent whatever you want to communicate from the style sheet to your runtime, you can pass over that bridge. Now, the reason I raised that I guess is like, the way I view that is it's like, it's just this building block that means you can actually do lots of interesting things. Things I couldn't even think about. I like I'm so tunnel vision on the specific things on building, but it's worth thinking about like, if you could communicate, if you were in a system like Sass and CSS modules, but you take the constraints off and you're like, I can actually export any static data I want from my style sheet over to my runtime, like what sort of frameworks and things can I build with that? Different people will have different ideas. Mark Dalgleish: In terms of what we're doing. Like I'm really happy with where we've landed. And I find that what it lets us do is focus more on the component layer. And so, yeah, to me, that's really the focus I guess, is trying to figure out how do we make our style sheets as expressive as possible, but keep that type safety, send stuff over the bridge to the runtime and what can we build with that? I still want to be surprised with things people are building. So hopefully it encourages someone listening to be like, yeah, I'm going to have to think about what I can do with this. Ben: Well, speaking of folks out there listening that are interested in vanilla-extract, you can get started at vanilla-extract.style. Definitely a bit of a mouthful on the domain there. But I guess I didn't even know .style was a TLD, but I guess it is, so vanilla-extract.style. Mark, thank you so much for joining us. This has been awesome. And yeah, take care. Mark Dalgleish: Thank you for having me. Brian: Hi. Thanks for listening. Please remember to like subscribe, email me if you want, even though none of you do, go to LogRocket.com and try it out. It's free to try then it costs money, but yeah, we'll see you next time. Thanks.