Skip to content

JavaScript Marathon: Building Your Own Style Framework With Vanilla Extract

Writing custom CSS throughout your app is time-consuming and error-prone. Relying on Tailwind or similar frameworks locks you into their way of doing things. But with Vanilla Extract, you can pursue the happy medium path: write type-safe CSS, create your own utility classes, and compile everything down to static CSS files at build time.

Tom walked us through how to setup and use Vanilla Extract to create themeable CSS architecture in our example app.

Helpful links

To learn more about Vanilla Extract, head over to their docs for a more detailed look into what working with Vanilla Extract is like.

With Vanilla Extract, we don't need to run any CLI commands like other processors. We create the appropriate *.css.ts files which get evaluated at build-time, and turned into properly scoped class names.

One thing to point out is our example is uses Vite. Don't forget to look at the config file we've modified that will look slightly different than the basic one created by the Vite CLI.

Install the dependencies

You can also reference the complete setup docs.

npm install @vanilla-extract/css @vanilla-extract/webpack-plugin

Create our folder structure

Let's get started by creating our folder structure that will hold our theme definitions.

In the end, your folder structure is entirely up to you, but for the sake of this example, we will create a theme folder and within that we will add theme.css.ts.

In this file, we will describe our different themes.

We also have a sprinkles folder which is where we define our "utility classes" of sorts. It operates in a similar way to how TailwindCSS operates. These sprinkles are styles we can include in other parts of our code.

We can see in our sprinkles file how we have defined certain custom styles.

And if we head over to our button.css.ts, we can see where and how our custom styles are used. It's like creating style variables within our CSS so we can keep a relatively consistent design feel across our app.

Our defined CSS styles will return classes with our properties defined. This is an example class from our Button/index.tsx: className={buttonStyle[color]}. This is a simple way to add different variants and styles to our components without bloating the component itself.

For the sake of covering all our bases, we also defined a few global styles.


Have a look at the example repo for a detailed look at how to use Vanilla Extract in a more in-depth way.

We hope this has helped you understand how Vanilla Extract is used at a higher level, and how you can leverage it to create your own type-safe CSS styles.