BYO CSS tokens to Tailwind v4's new CSS centric config

Adam Argyle March 18, 2024
Source
Tailwind v4 alpha brings CSS configuration, here's a quick intro to using it. Original Tweet Basic setup # I got most my information from the announcement post on Tailwindcss.com , it has good pointers for getting started. I chose to set up a Remix app with Vite . Once that's running, the new Tailwind default looks like this, a new magical @theme rule: @import "tailwindcss" ; @theme { } BYO props # At this point, you'll need your props in a CSS format. Open Props has always offered both JS and CSS versions of the variables, so getting them into this new config was swift. This isn't an Open Props pitch I promise! It's much more about CSS focused prop supported as configuration values. npm i open-props Vite supports the alias imports, so the props import into the config looks short n sweet like this: @import "tailwindcss" ; @import "open-props/style" ; @theme { } We're ready to start mapping. Font Sizes # Tailwind v4 alpha has proposed a simple way to opt out of their defaults with a swift entry into the CSS config: @theme { --font-size- * : initial; } Now we can add our own --font-size mappings and Tailwind will generate utility classes for it. The rules look like naming hooks, where if the custom property name on the left has --font-size in it, then it will generate font size utilities . The trick is to hook into the naming while also supplying your own design tokens as values. @theme { --font-size- * : initial; --font-size-00: var(--font-size-00); --font-size-0: var(--font-size-0); --font-size-1: var(--font-size-1); --font-size-2: var(--font-size-2); --font-size-3: var(--font-size-3); --font-size-4: var(--font-size-4); --font-size-5: var(--font-size-5); --font-size-6: var(--font-size-6); --font-size-7: var(--font-size-7); --font-size-8: var(--font-size-8); } Usage: < h1 class = "text-5" >…</ h1 > This same process was easily repeatable for colors, shadows, and more . Gradients # Going off the beaten path a bit, I followed the naming hook pattern idea and cross referenced it with the theme.css published in the v4 repo; I found I could bring all of the Open Props gradients in and Tailwind makes them available via the background-image utilities . @theme { --background-image-gradient-1: var(--gradient-1); --background-image-gradient-2: var(--gradient-2); --background-image-gradient-3: var(--gradient-3); … --background-image-gradient-30: var(--gradient-30); } < div class = "bg-gradient-30 dark:bg-gradient-8" > … </ div > Glad I went off the path. There's more to explore . Adaptive utilities # On to my favorite part, creating adaptive utililities. I really like adaptive custom properties , and I wanted Tailwind to generate adaptive utility classes for me. Instead of: < div class = "bg-gray-2 dark:bg-gray-12" > … </ div > I'd write: < div class = "bg-surface" > … </ div > It's possible, and easy to setup. I was happy to see I could configure Tailwind v4 to enable the workflow. Utility classes are just backed by props now right? And with colors, there's a clear naming hook. So what if instead of using Open Props values inside @theme , I make up some new ones, then I provide values for in light and dark media queries? So here's the light and dark theme: 2 text "ink" colors 2 surfaces a link color Tailwind sees the --color prefix hook and builds utilities. @theme { --color-ink-1: var(--ink-1); --color-ink-2: var(--ink-2); --color-surface-1: var(--surface-1); --color-surface-2: var(--surface-2); --color-link: var(--link); } But , --ink-1 and friends havn't been defined anywhere. So let's do that, with our design tokens. :root { --ink-1 : var (--gray-9) ; --ink-2 : var (--gray-7) ; --surface-1 : var (--gray-2) ; --surface-2 : var (--gray-1) ; --link : var (--indigo-6) ; } @media (prefers-color-scheme : dark) { :root { --ink-1 : var (--gray-1) ; --ink-2 : var (--gray-5) ; --surface-1 : var (--gray-11) ; --surface-2 : var (--gray-10) ; --link : var (--indigo-4) ; } } That's it , now I have a workflow like this, no noise about light or dark, that's configured higher up in the stack and templates don't need to deal with it. < div class = "bg-surface-2" > < header > < h1 cssName = "text-ink-1" >…</ h1 > < p className = "text-ink-2" >…</ p > </ header > </ div > Outro # I stashed this work in a repo called TWOP (TailWind OpenProps). Definitely checkout the theme.css file. Let me know what else you discover you can configure!

Discussion in the ATmosphere

Loading comments...