Customizing Twind config
8/3/2023, 12:44:06 PM
This is the third post in a series about my experience with Deno and the problems with Twind v0. This post won't be negative like the previous two and will, instead, offer advice on how to configure your Twind configuration file to make it work for you, instead of letting it work against you.
This post assumes you know how to write pure CSS to extend your Twind config. It won't teach you how to write CSS, but you should have a decent grasp of it if you are used to Tailwind/Twind utility classes.
Figuring out which version of Twind you have
The first thing you need to do before starting to configure your twind.config.js file is checking what version of Twind do you have running. The configuration for both is different, so that's something you need to know before we even do anything.
Check the main.ts file on the root of your project and see where twindPlugin is imported from.
Twind v0
If it's imported from $fresh/plugins/twind.ts (not versioned), then you have Twind v0.
WARNING! If you still are on Twind v0, I highly that you upgrade to Twind v1 first, before extending your $fresh/plugins/twind.ts file. That way, you can start using the stable version without having to put yourself through the pain that is using Twind v0 and neither you need to suffer through migration later. Migrating a non-customized$fresh/plugins/twind.ts file is incredibly easy and will take you 10 seconds to do. Regardless, if you choose to ignore this advice for whatever reason, this blog post will cover how to extend both versions of Twind.
Twind v1
If it's imported from $fresh/plugins/twindv1.ts (versioned), then you have Twind v1.
Configuring Twind v0
Let's go through the most common configurations people use for their CSS: animations, keyframes and classes. If you never edited your twind.config.js before, it should look something like this:
Adding Twind v0 animations and keyframes
Now to add functionality to this, let's be smart and work in a way that will make your life easier if you ever choose to migrate to Twind v1 later. Create 2 new objects, one will hold your CSS animation and the other will hold your CSS keyframes. You can do so just below the import.
Now, other than the selfURL, your twind.config.js file also needs to export a theme object with extend property that has 2 nested properties: animation and keyframes. You can assign the value of your customTwindAnimations and customTwindKeyframes objects to these nested properties and save your file. Your twind.config.js should look something like this now:
Adding Twind v0 classes
Adding custom classes to your Twind config is similar to adding animations and keyframes, but you use a plugins object instead of a theme with an extend property and nested properties. Once again, start with creating the object that will hold all the CSS classes:
Now your twind.config.js file also needs to export a plugins object which value will be the classes you want to add to your Twind configuration. Your file with classes should look like this:
You can have both keyframes and animations with classes all together in the same twind.config.js file. I stripped them to different code blocks only to have them focused in this tutorial, but mix and match to your heart's content.
Advanced Twind v0 configuration
If you have classes that are similar in nature, but slightly different, you can also nest them with a prefix, since Twind creates classes dynamically if you provide a function as the object property value. See the following example:
This example creates the custom-font-scale-largest, custom-font-scale-large and custom-font-scale-big classes that I use on this blog (inspect the <h1>, <h2> and <h3> elements on this page to see this example being applied). You can infinitely nest classes with this function form if you want to. It's very useful if you want to create custom classes for a component with a single prefix for everything, so that your team knows that they are not from a component library, but custom tailored by a member.
Configuring Twind v1
The twind.config.js configuration file for Twind v1 is different from Twind v0. One of the key differences is that you no longer export theme or extend, but rather the result of defineConfig. Either way, if you never changed your Twind v1 twind.config.js file, it should look like this:
Adding Twind v1 animations and keyframes
Twind v1 sees animations and keyframes as a single entity, unlike v0. Because of that, creating custom animations and keyframes is visually simpler to understand and parse, because they will be clustered together. They are also instantiated just like classesare, which also helps keeping all your custom configuration in one single place. To start, create an array with nested arrays that have the first value as the animation class name and the second value as an object that has the animation CSS and the keyframes. Check the example below:
Adding Twind v1 classes
Adding your custom classes to Twind v1 is very simple, you just pass a rules array as parameter to your defineConfig function. Inside rules, you provide another array with the first index being the custom class name and the second index being an object with all the CSS attributes you want that class to have.
Advanced Twind v1 configuration
If you have classes that are similar in nature, but slightly different, you can also nest them with a prefix, since Twind creates classes dynamically if you provide a function as the object property value. See the following example:
This example creates the custom-font-scale-largest, custom-font-scale-large and custom-font-scale-big classes that I use on this blog (inspect the <h1>, <h2> and <h3> elements on this page to see this example being applied). You can infinitely nest classes with this function form if you want to. It's very useful if you want to create custom classes for a component with a single prefix for everything, so that your team knows that they are not from a component library, but custom tailored by a member.
Migrating to Twind v1
So you have decided to migrate to Twind v1? Congratulations! You are making a decision that will help you not increasing your technical debt. Twind v1 is quite stable and vastly superior to v0.
Updating your main.ts file
All you need to do in this file is change the import of twindPlugin in your main.ts file from $fresh/plugins/twind.ts to $fresh/plugins/twindv1.ts (notice how this one has the v1 that the previous one didn't have).
Updating your unedited twind.config.js file
If you have never edited the configurations of your base twind.config.js file, your work here will be very minimal. All you need to do is copy the 10 lines of code in the block atConfiguring Twind v1 and replace your entire file content with that. You are done, save your files and feel free to customize your configuration file now.
Updating your customized twind.config.js file
If you have previously added customclasses or animations to your Twind v0 file, things get a little more interesting, because you have breaking changes to resolve. I'll do my best to enable you to fix those breaking changes yourself.
If your previous changes were following the tips from this post, your classes, animations and keyframes are stored on separate objects, which will make this upgrade easier for you.
First, delete everything from your twind.config.js file, EXCEPT your custom CSS objects (with animations, keyframes and classes), just comment those out for now. Now copy the 10 lines of code in the block at Configuring Twind v1 and paste that below your commented objects.
Below presets, but still within the object passed to defineConfig, add another property named rules. This requires an array of arrays, with the first index being a string with the name of the class you are creating and the second being an object with the CSS properties and values of said class.
To convert your old v0 classes to v1 classes, you can simply wrap up your old classes with Object.entries(yourOldClasses) and pass the result of that as a spread to the array required by rules.
Things get a little more complicated when you have to convert your animations and keyframes to a single class, because there isn't a simple way to merge both objects into one array with the proper format, so you gonna have to do some manual rewriting yourself, but it's fairly simple.
Regardless, what you need is a class that has the animation CSS as the first property and then the following property is @keyframes animationName just like you would write in plain CSS.
Converting dynamic Twind v0 classes to dynamic Twind v1 classes isn't a big deal, you only need to change the function parameter from a destructured array to a destructured object with the $$ property.
Closing Notes
Twind v1 is a lot more powerful than v0, it's fairly easy to extend its functionality and add things like preflight requests for fonts and much more.
Feel free to use the twind.style docs to further extend your configuration files. If something in this post doesn't make sense or is poorly explained, feel free toopen an issue on the Github repository for this website or reach out on Discord.
I'll probably edit this post as time goes on and I further extend my Twind configuration files and add here my experience. If you have a question about something else not listed here, it's most likely that I also don't know the answer, else I would have added here.