1. Introduction to TypeSafe Styled Systems
Hey, folks. I'm Josh Goldberg and this is TypeSafe Styled Systems, the future of CSS. I'm a full-time open source developer and maintainer, working in the JavaScript TypeScript ecosystem. I'm also the author of the Learning TypeScript book and a Microsoft MVP for developer technologies.
Hey, folks. I'm Josh Goldberg and this is TypeSafe Styled Systems, the future of CSS. A little bit about me first. Hello. I'm a full-time open source developer and maintainer. I work in the JavaScript TypeScript ecosystem, most notably TypeScript ESlint, the tool that lets you run ESlint and Prettier and other JavaScript tools on your TypeScript code. So I'm probably running on your dev machine in some way. I'm also the author of the Learning TypeScript book, and Microsoft MVP for developer technologies. So hit me up online, person, wherever, if you want to talk about any of those things.
2. Introduction to HTML, CSS, and Frameworks
Moving on to the talk, I will give you a caveat that it is a gross oversimplification. Before Joomla and Drupal and PHP and WordPress and all this stuff, there's HTML. Developers wanted more. So, we added CSS. But still pretty weak and not very powerful. Early CSS was great for what it had at the time. In order to get around this lack of power in CSS, we added frameworks. Bootstrap, for example, was a really popular one back in the day. And Bootstrap made everything look pretty similar.
Moving on to the talk, I will give you a caveat that it is a gross oversimplification. There are all sorts of things like Foundation and Joomla and Material UI that are relevant and I don't cover. But we only got 20 minutes. So let's begin.
Before Joomla and Drupal and PHP and WordPress and all this stuff, there's HTML. HTML was great. HTML was straightforward. This is an H one, a heading one with a hello world. It was plain. At the beginning, there was no way to style your document. This is your document. In modern browsers, black text, white background. Beautiful, simple.
But developers wanted more. Developers wanted styling. So, again, oversimplifying, we added CSS, cascading style sheets. Now you can describe, aha, my H one is fancy and I have this color and this background. So you can make your H one look like this with this centered text. Amazing. But still pretty weak and not very powerful.
Now, early CSS was great for what it had at the time coming before it. But it was still pretty weak and pretty not well-featured. And a lot of people made jokes about it. One of my favorite memes if you look up old bad CSS jokes is this Peter Griffin one with the curtains. So, in order to get around this lack of power in CSS, we added frameworks. Frameworks helped with both HTML and CSS. Bootstrap, for example, was a really popular one back in the day. Anyone who was doing web dev probably has some memory at the time of content or container, container fluid. And people who used the Internet long ago probably remember half the websites out there kind of looked like this, because they all used Bootstrap. And Bootstrap made everything look pretty similar.
3. CSS Pre-processors and CSS 3
Bootstrap was one of the frameworks that used pre-processors like LESS. CSS pre-processors like SASS and SCSS were developed to improve CSS. CSS 3 introduced new features like flexbox, making centering elements easier. The cycle of primitives innovation is repeated in the industry. CSS variables, previously used in pre-processors, are now supported in all evergreen browsers. The conclusion is that you probably don't need CSS anymore.
Bootstrap was also one of the framework times when we used a lot of pre-processors, which we still do to this day. Taking a look at this file from back in the day, this is using LESS, which is an old CSS pre-processor. You could do things like create custom properties or variables with this at or another dollar syntax. And you had these built-in functions like darken which would modify your colors or variables for you. And that was actually really nice because again CSS at the time was kind of weak.
There's an interesting lineage I think with the CSS pre-processors. There's CSS, then on top of that we had syntactically awesome style sheets or SASS, which often compared to Ruby because they had similar syntax to that in CoffeeScript. Then we had LESS which is leaner style sheets. It looked a little bit more like CSS, people like that. So then we also jumped onto that pattern with SCSS which stands for, you guessed it, Sassy CSS. It's a sequel, a predecessor to some of the things we have today. Now, this actually kind of mirrors the pre-processors that we saw in the JavaScript landscape. CoffeeScript came out with very Ruby-like syntax, and then we have Babel and TypeScript come after that which are kind of like less in that they were closer to the core.
Anyway, at the same time, people were working on and thinking about future additions to CSS, and eventually we had CSS 3 come out. And it's still coming out to this day. We're constantly adding to new CSS areas. One of the things you can do in CSS that you couldn't as easily before was center. Amazing! You can use this awesome new flex thing, and you can say, for example, that my container height is 100%, and it's flex with centered, horizontal, and vertical. So I don't like hearing people saying anymore, oh, it's impossible to center in CSS. It used to be kind of difficult, but they worked on it. And this whole cycle that we've seen here of primitives and frameworks and all this is repeated continuously in our industry and others. And I call it the cycle of primitives innovation. First we get a bunch of primitives like CSS which are better than what we had before. And then we ideate on the common difficulties, we figure out some way in user land to make some competing solutions for them, say frameworks or meta processors. And then we build that into the language. While CSS and less and SASS and SCSS are all jumbling around, people working on future CSS. And as an example to that in particular, we now have CSS variables. You can do those at or dollar sign things from less and SASS just in CSS Pure. And this is supported in all evergreen browsers. Which leads us to our first conclusion of the talk, you probably don't need a CSS anymore.
4. Innovation with JavaScript and CSS
Most web sites that use CSS or an equivalent, use it for features that now exist in CSS. You probably don't need a CSS anymore, but not definitely. Up to you. We also innovated on the front end space with JavaScript. First we started messing around with jQuery. Then we added a round of iteration. Then we got to the component driven architectures with Angular and Ember and React. And in order to support this explosion of front ends being dynamic, we added ways to have dynamic CSS. One common and popular to this day option is CSS modules. We need more. Let's take a look at another approach, style components, or CSS and JS. Here, we have a container, and then H1, this pair of elements that are created with styled.
I can't say definitely, there are features that adds on top of CSS. But across my time in consulting full time open source and so on, most web sites that use CSS or an equivalent, use it for features that now exist in CSS. Most but not all. So, you probably don't need a CSS anymore, but not definitely. Up to you.
Anyway, we also innovated on the front end space with JavaScript. It used to be you just made your website in HTML or some server language like PHP. But now we have JavaScript first front ends. First we started messing around with jQuery. Again, this talk is an oversimplification. Then we added a round of iteration. Like background and knockout that made things really dynamic. Then we got to the component driven architectures with Angular and Ember and React. Then we innovated on that with more Angular and solid and Svelte and React and Vue. And in order to support this explosion of front ends being dynamic, we added ways to have dynamic CSS.
One common and popular to this day option is CSS modules, where you define your CSS in some file. In this example, I've been using SCSS for variables. That was popular back in the day. And then in your JavaScript or React save file, you import the styles and use them as variables. Here we have similar to what was done before, where we have our colors and padding stored in a SCSS variable, and then our CSS refers to them. And if you want your JavaScript side to be dynamic in which class gets pulled in, you can say use a utility like CX or class names that takes in a bunch of things that are strings or falsy things or objects or arrays or so on, and then matches them all together into one class name. In this example, the button adds in the styles.pressed class if it was pressed. And this works. Honestly, a lot of my sites that I write to this day use CSS modules. For straightforward websites, or for ones that don't change much, this is fine. But, we need more. There are always more fancy websites coming out there. So, let's take a look at another approach, style components, or CSS and JS. I personally used emotion, which was a competitor to styled, a bit more, but they're around the same. Here, we have a container, and then H1, this pair of elements that are created with styled.
5. Styling with JavaScript and CSS
You can define your CSS in your JS using JavaScript variables or TypeScript code. This approach works but can be challenging to scale with complex websites. Developers today have four main needs for styling: convenience, assistance, refactorability, and themability. However, performance is often overlooked. R style components cart slash cart P can be difficult to work with due to raw strings.
and then the tag name, and then you define your CSS in your JS. So, instead of using CSS variables, you could just use JavaScript variables or TypeScript code. Here we have color background, which gets interpolated into the H1 string. This is actually pretty nifty. I think it's kind of clever. If you want dynamicism, you can add in these component props, like $pressed, where it becomes at runtime, whatever you need it to be. So, this works. And I still see websites doing this. But it can be hard to scale, because we added some really beautiful, really snazzy fancy JavaScript front ends.
Look at this beautiful website over here for this conference. We have this dynamic homepage with this header thingy on the bottom. And then inside the website, we have all of these dynamic components with modals and similar fonts but different colors sometimes. And you know what? They're complicated, these websites people are making. Developers today have competing, interconnected needs for styling. And I'd say that they would be categorized in these four-ish needs.
The styling needs to be convenient. It needs to be easy or at least straightforward to write new styles. You don't have to jump through three boxes in a new file. It should be assistable. The IDE should give you autocompletions and let you know when you mess up. It should be refactorable. If you want to, let's say change a color or switch the DAB bar from top to bottom, it should be relatively straightforward to do that. And it should be themable. People these days are always looking at light mode versus dark mode and high color contrast and all sorts of other ways of changing the colors around.
Now, these four do miss one very important concern. Performance, which I think is important. Folks generally agree is important, but oftentimes, it's hard to budget for. But I digress. R style components cart slash cart P, eh, they're not great in my opinion. It can be hard to mess with those raw strings, even if your IDE has an extension to syntax, highlight them like CSS.
6. Alternative Approaches to CSS Styling
Another approach I actually strongly in the day was a family of libraries epitomized, I think by Glamour, which was a utility that would allow you to pass in an object of styles to the CSS function, which would then spit out classes for you. Fun fact, actually, this was made by Sunil Pai, who ended up doing a lot of work at React, and now works on PartyKit. But another approach that a lot of folks these days like is Tailwind. Hot take, Tailwind's actually pretty great. It is convenient as all heck. If you want to be dynamic, well, there's strings. Another advantage of Tailwind is that it's docs are fantastic.
Another approach I actually strongly in the day was a family of libraries epitomized, I think by Glamour, which was a utility that would allow you to pass in an object of styles to the CSS function, which would then spit out classes for you. I thought that was really clever. I liked how it blended CSS, as in these are just CSS properties at the end of the day, with good JavaScript, TypeScript primitives that you're still working in your JSTS code. And if you want dynamic things, you could, well, instead of using a plain object, have a function that returns that CSS plain object that takes in props.
Fun fact, actually, this was made by Sunil Pai, who ended up doing a lot of work at React, and now works on PartyKit. Congrats again to PartyKit for getting me started. Really exciting. And unfortunately, Glamour hasn't had a commit in years. Such is open source. But another approach that a lot of folks these days like is Tailwind. And don't worry. I'm not finishing with Tailwind. I know this is a hot take controversial thing to talk about. Hot take, Tailwind's actually pretty great. I don't personally prefer it, but I recognize it's real straightforward. It is convenient as all heck. I mean, all you got to do is declare your classes in these strings. And they're applied. And then the Tailwind builder processor thing can optimize your performance. It's pretty great. If you want to be dynamic, well, there's strings. So, you can concatenate them together. If you have this button pressed state, you can use that to concatenate different strings. Now, there are extensions to Tailwind that make this a little prettier, but this is the most common way I've seen folks do it in the wild.
Another advantage of Tailwind is that it's docs are fantastic. Like, seriously, shout out, congrats to the Tailwind docs team. Y'all do a good job. It makes it a lot easier to work in CSS or styling in general when you have fantastic docs. So, yeah, I would say Tailwind is a pretty good cart solution. It's convenient, it's assistable, it's refactorable, it's themeable, it has built-in support.
7. Advanced Style Systems: Chakra UI and Theming
Tailwind is a good style system, but it has limitations. I'll discuss more advanced options, like Chakra UI, which allows you to define styles as props on components. This approach is accessible, well-documented, and supports theming. It represents the epitome of what style systems could be.
Tailwind is actually a pretty good style system. It generally supports what we need, and most websites today, I think, are totally fine to be built on Tailwind. But I do have some gripes. Tailwind is not TypeScript first class, which is why I'm going to talk about some more things after this that are. Tailwind is an extension on top of CSS fundamentally. It lets you define a bunch of classes with its primitives and then work with them. But that means that things like this are very hard to spot as errors or not errors. How does Tailwind know if what is a built-in class or a class you defined or nonexistent.
So I want to move past Tailwind. I want to talk about a few libraries that are a little bit more fancy than it. And I call these component libraries. Take a look at a popular one, Chakra UI. This is how you would do something similar to what we saw in the Tailwind slide with Chakra. Chakra provides a bunch of components, such as a box, which is a general purpose one and then slightly more specific ones such as heading. And instead of defining your styles as class strings, you actually define them as props on the components themselves. Box, flex. A line item equals center. Which I think is a really nice approach. It's super accessible in the IDE. It's well documented. If you want dynamicism, well, again, they're just props, just CSS and JS. So you can do that. And with Tailwind also, you can theme them. Tailwind and Chakra and Simbler all support the ideas of color themes. Which is, I think, a really good idea. That if you have, let's say, a brand color, you use that in your components instead of hard coding it to a specific hex code. And I want to hone in a little bit on this. Because personally, I think this is the epitome of what a lot of style systems could look like. You have your components, you can say what DOM tag they render as, and then you can specify your props, which should adhere to your design system tokens as components. As component props.
8. Chakra UI and Style Systems
Chakra UI is a component library that also exposes a style system. It tends to get bogged down by trying to do all those things. Tailwind is just the style system, providing raw colors and primitives. Chakra UI provides a lot and is popular, but there are more interesting innovations happening in style systems. One exciting innovation is Vanilla Extract, where you define tokens and use them to create classes for components.
Chakra actually does something kind of clever inside to get autocompletion on these props. It defines a lot of string values as the union, or all the different possible strings, those literals. And then it also adds string and empty object there in that TypeScript type. Which allows you to say get autocompletion on the props, but then unfortunately also allow any possible value. So, it's a little unfortunate that you can use that nice little TypeScript trick and then lose a little type safety.
It's convenient because it means you can specify whatever values you want. But the token types here aren't strict, which is a bit of a feature request that I have as a TypeScript user to a lot of these style systems. Now, I will say the Chakra UI team is great. This is not a dig at Chakra. They are actually working on this problem. It's quite difficult. So, seriously, love to the Chakra and folks who have been working on this. But it is a little bit away from being the primary way that you use Chakra in production. I couldn't find it on the Chakra site. So, even though I know there's progress being made, at its core, Chakra UI is a component library that also exposes a style system, which means that it does tend to get bogged down a little bit by trying to do all those things.
Looking at it visually, Bootstrap was a style system that also exposed a few small components, like badges and buttons. Tailwind is just the style system. It just provides you the raw colors and the way to customize and use them on your own. Colors and other primitives. Chakra UI provides a lot, which is awesome. A lot of websites are totally fine just using Chakra UI. If you need a component library on top of Tailwind, there is Tailwind UI. But I want to focus on where I think the really interesting innovations are happening. I want to focus on the style systems. Because the foundations upon which we build our component libraries are really interesting. And one really exciting innovation that I want to espouse about now is Vanilla Extract. This is a kind of new approach to libraries over the last three to five years that I've started to see get more popular. Which is you define your tokens and JavaScript brands, the way one would build a design system. Let's say you've got your color primitives or your space. And then you use those to create classes for your components using the framework.
9. Vanilla Extract and Rainbow Sprinkles
In Vanilla Extract land, you can use class names in your components and it becomes well-optimized CSS classes. They even use CSS variables for theming. If you mess up, Property Wet can give you a type error. Vanilla Extract is an innovative style system. Wayfair's rainbow sprinkles library on top of vanilla extract allows you to create boxes with dynamic values. It's new and experimental, and type safe systems for style are coming.
In Vanilla Extract land the right side of the screen would be in your .css .ts file. And then similar to Glamour before, you can use those class names in your components. And behind the scenes it becomes all these nice well optimized idiomatic CSS classes. Or they even use CSS variables for theming. And one really nice advantage of these that I'm very excited about is if you mess up, if you type in the wrong name, because it's all JavaScript-y type script on the inside, Property Wet can give you a type error. Amazing! Love typescript. What a treat.
So this doesn't do as much for you. This is just the style system. But it's a really innovative of looking at things. And I'm excited about it. I hope we continue to work on things like vanilla extract and build component libraries on top of them. But I want more. There's always more that can be done.
One last cool thing is a rather experimental library by Wayfair on top of vanilla extract called rainbow sprinkles. Rainbow sprinkles allows you to set up vanilla extract the same way. This is the same code from the previous slide. But then you can also create this box abstraction on top of it, this rainbow sprinkles concept, where you're describing which of your properties say align to the DOM, the native attributes, line items is just raw CSS, or have vars.color or another variable, such as with background here. And then that allows you to build boxes, kind of like Chakra UI's boxes, where you have box align items equals center, display equals fex, but then box on the inside says background equals background. And similar to Chakra, if you want dynamic values, refer to them in JavaScript plant. Yes, awesome. I think this is really cool. And we can even catch what, right? Nope, it's not type safe. I couldn't figure out a way to get it to be type safe. So, it's very new and experimental. And it's not the only thing that does this. For example, style components has this really awesome builder called style system. Type safe systems for style are coming. But it will be a little bit before they're super ready. Get excited.
10. Opinions on Design Systems and CSS
Start playing around. Personally, I think most projects should use a design system and separate tokens from app logic. Each major system has its strengths and weaknesses. It's important to have nuanced opinions and consider advantages and disadvantages. Check out the links for more information.
Start playing around. At the end, I'll show some resources, but beware, some of the stuff is new.
Now, because I've got a minute and we're talking about CSS and stuff, I feel weirdly obligated to mention my opinions on here. I have them. So, these are just my opinions. Please don't think of me as like the thought police, or trying to be the thought police or whatever. This is just my perspective.
Personally, I think basically all, not all, but most small or larger than small projects should probably use a design system. At the very least, try to separate tokens out from your app logic. It'll save you a lot of time if you use your brand variables, your colors at the very least, instead of defining raw values in line. If you ever have to change them, it's a lot easier.
I also think that all three major systems I showed, using CSS on its own, tailwind, style systems, CSS and JS in general, they each have their strengths and weaknesses. It's really hard to make a claim that any are universally good or bad. Because, honestly, we're all still iterating. We're all getting better. What's considered great today is going to be considered probably mediocre at best in 10 years. So, if you see someone make a statement that tailwind bad or Chakra good or whatever, I would recommend if you don't know or at least believe it to be true, or more specifically if you haven't put in good faith effort to validate that it's true, please don't amplify the opinion.
Again, this is just my perspective online discourse. But things like tailwind bad, tailwind the only acceptable choice, real devs, insert thing here, I don't like this. I think it's a little shallow. I would personally lean towards nuanced opinions. Like I prefer thing over or under other thing for reasons. There are advantages and disadvantages always. Those are just my opinions. So let's close out. Let's have some thoughts. I have nice links on these slides here which are also linked on my website to vanilla extracts docs, the wayfare docs for rainbow sprinkles. I got code examples for all the code slides I showed. And also gamut is Codecademy's design system that uses a lot of the glamour or vanilla extract style features. Which I'm really excited about. So if you want to talk to me about open source again, I'm always happy to chat. So thanks, y'all.
Comments