Create CVA Variants0:00
Let's take a style lookup classes that we've created manually and use CVA to streamline the process. All right, so the first thing we'll want to do is obviously import CVA and we are going to create a myButtonVariants function that calls that CVA function. So maybe up here after the type that we will, you'll see delete soon, I will create a const, myButtonVariants
after the type that we will, you'll see delete soon, I will create a cons, my button variance and we are going to call CVA from class Variance Authority. And so if I hover over this, you can see that CVA can receive a base, which is our base classes as a first argument and then a config, which is where we can pass multiple variants. So I'm going to copy the string of the base classes here and I'm going to paste it as the first argument.
So I'm going to copy the string of the base classes here and I'm going to paste it as the first argument. So with this, we sort of have taken care of the base classes here. And as a little exercise, I'm going to go here and remove the base classes. So that's going to temporarily break the button and yet we've lost our border radius and whatever was passed in the base classes, but now we should be able to replace that with our
and whatever was passed in the base classes, but now we should be able to replace that with our myButtonVariance. But the return from the CVA function is an actual function that you can call. So we will call myButtonVariance like this and look, our base styles are back and we are back to normal working buttons like we expecting. That means I can go and delete the base classes from my code,
Define Size and Look1:28
That means I can go and delete the base classes from my code, but CVA wouldn't be super useful if it was just to handle base classes. But what we can do is pass a config object as the second argument. So here I will have comma and I will pass an object which contains variants. And you can see there's other options like defaultVariance, compoundVariants, et cetera.
And you can see there's other options like default variance, compound variants, et cetera. And here inside the variance I want to take care of the size possible variants and the look possible variants. So inside I'll have a keyhole size and inside of there I will paste my three keys like so. But as I do this, here's something important to understand Down here, we were telling the size classes object, what shape it should have based on the type.
Down here, we were telling the size classes object, what shape it should have based on the type. And what we're going to do here eventually is do the exact opposite. We are going to let this size variant define what the type will be. In other words, we will get rid of that and then infer it from the CVA variant size. Let's keep it on for now. But eventually we will remove that.
Let's keep it on for now. But eventually we will remove that and let it be generated through the CVA function, which is super, super cool. So I have my sizeVariant and we are also going to do the same for copilot. Help me the lookVariant. Absolutely. And so I can now delete all of this assuming copilots did its work. So things are going to be broken.
of this assuming copilots did its work. So things are going to be broken because we rely on those here. But I can also remove this here. You might think that's all we need to do. But you can see that TypeScript is telling us, Hey, you're not using size or look anywhere. What are you doing with this? And so if we take a look at what happens now with just my button variance, you'll see
And so if we take a look at what happens now with just my buttonVariance, you'll see that all our buttons look exactly the same. And they basically only have the base classes. So calling the buttonVariance function without any argument, we'll just have the base classes. What we want to do is also pass the size and look. And so we want a size key, which is going to be the size prop passed to the component. And I can just keep the key as it has the same name.
to be the size prop pass to the component. And I can just keep the key as it has the same name and do the same for look. So now we receive the size and look properties in the component and then we pass them to the button variance. And so if size is medium, it's going to go look for size, medium and output this. And if look is outline it's going to go look outline. And so now I believe that with that setup,
And if look is outline is going to go look outline. And so now I believe that with that setup, our buttons should be back to working normally and yep, they do. Fantastic. And by the way, quick aside, you might see, and I think Shazi NUI does it this way where the class name is passed inside the CVA variant like this. And that also works. And this is because the CVA function out of the box also accepts a class.
And that also works. And this is because the CVA function out of the box also accepts a class or class name property that it will merge with the rest of the stars. So if we look at the chat and UI button, which is this one, and we go at the end, you can see that the class name will be inside the button variant function call, which is the return of the CVA function. Alright? But now here's the really cool part with CVA.
Infer Types from CVA4:31
which is the return of the CVA function. Alright? But now here's the really cool part with CVA. And like I mentioned before, we are going to get rid of size and look here in our type. And we are instead going to infer these from the variance here in the CVA function. So we're going to keep children and className. And here before the component props, I will go and variantProps, which is a type from CVA that I've just imported here.
and variant props, which is a type from CVA that I've just imported here. And it can receive here type of my button variance. So that line here essentially is the equivalent of what we had for size and look manually, but it's going to create it from these values inside the variance object. So everything should still work the same. And if I try here to see what values are available, you can see that they are here as well.
And if I try here to see what values are available, you can see that they are here as well. So we have no manual type definition for our style variance. All we had to do is create the variance in the CVA function and then the types are automatically generated from that, which is super cool. So if I were now to add an XL property and go px-7 py-4, I can go in the welcome page and add the extra large button with the size Excel, which has been added to the size prop.
Set Default Variants5:47
and add the extra large button with the size Excel, which has been added to the size prop. And here's our extra large button, we have our variance here and I'm going to add a default variance here. And so I can say that the size should be medium and the look should be primary. And by doing this I can remove more of my manual code here and I can remove the default value assignments because they are going to be assigned to these and everything still works.
Add Compound Variants6:15
because they are going to be assigned to these and everything still works. The default button has the medium size. Here you also have compound variants. This is defined as an array. And basically it's scenarios where a specific circumstance happens between variants. So for example, a button that has both the size large and the look outline should have specific classes added to it.
and the look outline should have specific classes added to it. So let's do exactly that. If the size is large and the look is outline, we want to add some class name and let's go again with uppercase to keep it simple. So whenever we have a button that is large and with the outline look, it should be uppercase. Let's add one more because we actually don't have a large
and with the outline, look, it should be uppercase. Let's add one more because we actually don't have a large outline, but here I will add the size of large and I'm expecting this button to have an uppercase text and you can see it right here. Pretty cool. And compound variants can target multiple scenarios. So for size we could have an array of large and medium. And then for the look we could have outline or primary. So now any button that is large or medium and outline
And then for the look we could have outline or primary. So now any button that is large or medium and outline or primary will be uppercase. So there should be a few. And yet these two are large, medium, and primary. And these two are large, medium and outline. As you can imagine, compound variants are pretty powerful and you can do a lot of stuff with it. And the last thing I want to show you is something that we don't often think about,
Reuse Variants Outside Component7:40
And the last thing I want to show you is something that we don't often think about, but by using CVA, we have decoupled our styles from the actual component. If we want to looking at the shared CNUI button, you'll see that the button variance here with all the CVA styles has been at the end exported here, which means we can import it and use it on any other element. So in the welcome page, I could have an anchor tag
and use it on any other element. So in the welcome page, I could have an anchor tag that we want to make look like a button. And so it has an href of whatever, and it's called this button link. So right now it's going to look just like a link text because it's not styled at all. But I could pass a class name attribute and go and reach for the button variants, which is going to be imported from the chatcn-ui Button component.
and reach for the button variance, which is going to be imported from the chatCNUI button component and call the function. And remember, without any arguments, it's going to be the default style, which in chatCNUI is like this one. But then I could reach for the button variance again with auto completion. And so in variance, we have all of this so we could try something like destructive.
And so in variance, we have all of this so we could try something like destructive. Whoops. Let me quickly add a flex-wrap here. flex-wrap. So it wraps nicely. And so our red button looking element is an anchor tag that has all the classes applied by class variance authority. So we basically are doing all the style variant matching and merging with CVA and then we have that available as a string of classes.
and merging with CVA and then we have that available as a string of classes. Alright, that's all I have to say about class variance authority. Hopefully you really like it. And now you should be able to look at the button component from SHA CNUI and understand exactly what's happening all along.
