Multi-Theme Tailwind 16 exercises

Dynamically Define Theme Colors In Your Tailwind Config

As mentioned, the solution will be some similarities to the getCssVariableDeclarations function we wrote previously.

Here’s that function’s code for reference:

function getCssVariableDeclarations(input, path = [], output = {}) {
Object.entries(input).forEach(([key, value]) => {

Loading solution


0:01 Our code will have similarities to what we've done in the previous step, but it's also a little bit different. Here is the function we've created before, and underneath, we're going to work on the getColorUtilitiesWithCssVariableReferences here.

0:15 Just like earlier, we'll want to keep tab of a path which starts as an empty array. We don't need an output object here. We're not going to populate an object. Instead, we're going to return the object that we construct.

0:27 Once again, we go with Object.entries and grab our input, but instead of forEach, this time we will map over it and grab the key and value. Inside of there, we'll construct our newPath, path.concat key. If the typeof value is not a string, we're going to want to call that function once again, where the input will be the value and the path will be the newPath.

0:56 Up to this point, you can see the code is quite similar, but now it's going to change. We're using .map, and we actually don't want to return an array. We want to return an object. We can use object from entries to wrap around our code to achieve that.

1:10 Up here, I will wrap the Object.entries inside an Object.fromEntries like so. We need to return this. Object.fromEntries expects an array with two things, so instead of just calling the function here, we're going to return an array which is a key value pair where the key is the current key, and the value is that function call.

1:37 Since we're returning the array, we don't need an L statement, because the code is going to stop execute here if the condition is met. In case that it is a string, what we want to return is an array where the key is the current key and the value, we want to achieve this syntax here, rgb with the CSS variable color composed with the alpha-value.

2:02 I will copy this and up here use back ticks and paste that here, and instead of the hard-coded CSS variable, this is where our newPath is going to come handy. We have kept track of where we are in the tree and we're going to output this with newPath. Remember it's an array, so .join with a - separator.

2:26 That was a lot. Let's actually try to console.log the result once again. Inside the addBase function here, I will console.log getColor, blah, blah, blah, lots of letters, and the input will be themes.base. Let's save that and let's make this a little bigger. What do we have?

2:48 We have this primary object, and then the keys with the correct syntax, and then this nested hierarchy, which seems to be exactly what we want. Moment of truth, let's try and replace the hard-coded theme extension with our new function that should generate the correct utility class sets.

3:07 Let's start by deleting the entire colors object extension. Here, instead of the object, we're going to getColorUtilitiesWithCssVariableReferences. We only need to generate the first theme, so let's go themes.base and hit save. That's looking promising. Let's scroll down, primary-900, and look at this. Secondary-some-nested-color. It's working beautifully.

3:36 If I go into base theme from the JSON file, and here create even more nesting -- omg, yes, it, works -- and paste that up here, look at this. We are matching the CSS variables generated, and then the utility class names, and these two paths work together to create this theming strategy that now is super dynamic.

4:03 You can see the three colors are the same. The reason is this variable only exists in the first theme. One thing that is important with this approach is you need to take the first theme, which is base, and this is like the blueprint that should be matched by other themes, because otherwise, it's going to generate CSS variables based on the first theme that don't exist in the second one.

4:27 If I was to copy the secondary part of the base theme, and here in rainforest replace that and change the color to black, you can see that now it's updated properly.

4:39 I'll backpedal on the changes here, and just like we did before, we're here assuming that themes.base exists, and we should not do this. Instead, let's do Object.values and grab the themes, and then grab the first instance.

4:57 All right, take a deep breath. Maybe take a break. This was a big one. We have one more step to go.