Large Tailwind Components — What to do About All Those Classes

Frontend FYI – by Jeroen
21 Nov 202225:18

Summary

TLDRThe video script discusses the challenges of managing complex CSS class names in Tailwind, particularly for components with multiple variants like buttons. It introduces Class Variants Authority (CVA) as a solution, demonstrating how it simplifies the creation and maintenance of consistent, structured styles for components within a design system. The script compares traditional Tailwind CSS with CVA, showing how CVA can improve readability and maintainability, especially beneficial for large-scale design systems with numerous component variants.

Takeaways

  • 😕 Tailwind can be messy when defining class names for components with many variants, like a button with different styles and sizes.
  • 🛠️ The speaker used 'stitches' for styling in CSS and JS, highlighting its structured approach to defining component styles based on props.
  • 🔍 'Class Variants Authority' (CVA) is a library that helps manage Tailwind class names for complex components, similar to 'stitches'.
  • 🎨 The video aims to build a button component from Shopify's design system, comparing the process with and without using CVA.
  • 📝 The speaker discusses the importance of preventing the creation of invalid component variants in a design system.
  • 🧩 The process involves defining props and variants for the button, including size, modifier, and boolean properties like 'disabled' and 'loading'.
  • 📉 The speaker identifies issues with maintaining and readability when using plain Tailwind for complex components.
  • 🔄 The video demonstrates how to convert a Tailwind-based button to use CVA, streamlining the class name generation process.
  • 🛑 The script points out the need to avoid duplicate CSS properties in Tailwind to prevent specificity issues and potential bugs.
  • 🔑 CVA's structured approach helps in maintaining a consistent style application across variants and reduces the risk of typos.
  • 🚀 The video concludes that CVA is beneficial for large components within design systems, but should be used judiciously to avoid overcomplication.

Q & A

  • What is the main issue discussed in the script regarding Tailwind CSS?

    -The script discusses the issue of creating a big mess when defining class names for components with many variants in Tailwind CSS, especially when those components have various properties that change the class names.

  • What is a potential solution to the class name mess in Tailwind CSS mentioned in the script?

    -The script suggests using a library called class-variant-authority (CVA) as a potential solution to manage class names more effectively in Tailwind CSS.

  • What is Stitches and how does it relate to the problem discussed?

    -Stitches is a library mentioned in the script that was used for styling components in CSS and JS. It allows defining an object called 'variants' to manage different properties of a component, which is similar to what CVA does for Tailwind CSS.

  • What is a compound variant in the context of the script?

    -A compound variant in the script refers to the combination of different variants of a component, such as a primary button that is also disabled, which can affect the styling in a way that needs to be managed.

  • What is the purpose of using CVA according to the script?

    -The purpose of using CVA is to improve the maintainability and readability of the code when dealing with complex components that have many different variants and to avoid the mess of manually defining numerous class names.

  • What is the 'variants' object in CVA and how is it used?

    -The 'variants' object in CVA is used to define different styles for a component based on its properties. It is an object where each property can nest different properties, and each of these will map to a property of the component, affecting the rendered CSS.

  • How does the script suggest improving the workflow when building a button component with many variants?

    -The script suggests using CVA to generate class names based on the button's properties and variants, which can streamline the process and reduce the potential for errors and duplication in the code.

  • What is the downside mentioned in the script about creating too many variants?

    -The downside mentioned is the possibility of creating variants that are not intended or do not make sense, such as a 'primary destructive' button, which could lead to inconsistencies in the design system.

  • What is the importance of specificity and order in CSS when using Tailwind CSS, as discussed in the script?

    -The script highlights that in Tailwind CSS, if multiple classes with the same specificity are defined, the one that appears last in the CSS file will take precedence. This can lead to unexpected results if duplicate properties are defined.

  • What is the recommendation for using CVA in the script?

    -The script recommends using CVA for complex components or large design systems where maintaining a structured and predictable codebase is crucial. It should not be used as the default for every component to avoid overcomplicating simple implementations.

Outlines

00:00

😖 Tailwind's Class Name Complexity

The speaker expresses frustration with Tailwind CSS's flexibility, which can lead to messy class names when defining variants for components like buttons. They mention the challenge of handling different states and sizes, which can result in a disorganized codebase. The speaker contrasts this with their previous experience using the Stitches library, which provided a structured approach to defining component styles based on props.

05:01

🛠 Introduction to Class Variants Authority (CVA)

The speaker introduces Class Variants Authority (CVA), a library that aims to bring structure to Tailwind CSS by allowing developers to define variants and modifiers in a more organized manner. They compare CVA's approach to Stitches and demonstrate how it can be used to create a button component with various styles and states, making the process more maintainable and less prone to errors.

10:02

🔍 Deep Dive into Tailwind Class Name Generation

The speaker provides an in-depth look at generating Tailwind class names for a complex button component, highlighting the difficulties in managing different sizes, states, and modifiers. They discuss the specificity of CSS and the importance of avoiding duplicate properties to prevent unexpected behavior in production. The speaker also points out a bug in their code related to padding properties and suggests a fix.

15:03

📝 Implementing CVA for Better Maintainability

The speaker begins the process of converting their button component to use CVA, emphasizing the improved structure and readability it offers. They walk through the steps of defining shared class names, variants, and modifiers within CVA's configuration. The speaker also discusses the benefits of using CVA for creating design systems and managing complex components.

20:05

🔄 Refactoring with CVA for Enhanced Structure

The speaker continues the refactoring process, moving various properties and modifiers into the CVA configuration. They address the challenge of defining compound variants and suggest improvements to CVA that would reduce the need for duplicate code. The speaker also discusses the importance of consistent code patterns for maintainability within large projects.

25:07

🎉 Conclusion on Using CVA in Design Systems

The speaker concludes by summarizing the benefits of using CVA for managing complex components within design systems. They emphasize the improved predictability and structure that CVA brings to the development process. The speaker advises using CVA judiciously for large components with many variants and encourages viewers to share their experiences with the tool.

👋 Final Thoughts and Call to Action

In the final paragraph, the speaker invites viewers to share their experiences with CVA, especially in production environments. They encourage subscriptions and likes and signal the end of the video with a promise to see the audience in the next one.

Mindmap

Keywords

💡Tailwind

Tailwind is a utility-first CSS framework that provides developers with a set of pre-defined classes to quickly build custom designs without writing CSS from scratch. In the video, Tailwind is discussed in the context of its flexibility and potential downside of creating a 'big mess' when defining class names for components with many variants, such as a button with different styles and states.

💡Class Names

Class names in the context of CSS and Tailwind refer to the identifiers used to select and style elements in HTML documents. The video script discusses the challenge of managing class names when creating components with multiple variants, highlighting the complexity that arises from Tailwind's freedom in building styles.

💡Variants

Variants, as used in the script, refer to the different states or appearances a component can have, such as a button being primary, secondary, or destructive. The video emphasizes the difficulty in managing the class names for these variants within Tailwind, and how tools like Class Variants Authority (CVA) can help streamline this process.

💡Stitches

Stitches is a styling library mentioned in the video that allows for the creation of components with variants in a structured way. It is used as a comparison point to illustrate how a library can help manage styles and variants in a more organized manner compared to plain Tailwind.

💡Compound Variants

Compound variants refer to the combination of multiple variant properties that affect the styling of a component. The script uses the example of a primary button that is also disabled, which may require a different color scheme, to illustrate the complexity of managing these combinations in Tailwind without additional tools.

💡Class Variants Authority (CVA)

Class Variants Authority, or CVA, is a library introduced in the video that helps manage class names for Tailwind components with multiple variants. It is shown as a solution to the problem of creating a structured and maintainable way to handle complex component styling within Tailwind.

💡Design System

A design system is a set of reusable design components and rules that help maintain consistency and efficiency in product design. The video discusses the importance of a design system when using Tailwind and how CVA can be integrated to create a robust design system with clear boundaries and component structures.

💡Prop

In the context of React and the video, a prop (short for property) is a value that is passed from a parent component to a child component. The script discusses how different props, such as 'variant', 'modifier', 'size', and 'disabled', are used to change the class names and styling of a Tailwind component.

💡Specificity

CSS specificity is the set of rules that determine which style declarations are applied to an element. The video script mentions specificity in the context of understanding why certain styles are applied over others when multiple classes are defined in Tailwind, and the importance of managing specificity to avoid unexpected styling issues.

💡Maintainability

Maintainability refers to the ease with which a piece of software can be maintained or modified. The video emphasizes the importance of using tools like CVA to improve the maintainability of code when dealing with complex components and variant styling in Tailwind.

Highlights

The complexity of managing class names in Tailwind when dealing with components that have multiple variants.

The use of the library 'stitches' to manage styling in CSS and JS with a structured approach to defining component variants.

Introduction to 'class-variant-authority' (CVA), a library that helps manage Tailwind class names for complex components.

CVA's similarity to stitches in functionality but tailored for Tailwind CSS.

Building a button component from Shopify's design system using both plain Tailwind and CVA to compare workflows.

The challenge of creating impossible variants in a design system to prevent incorrect component combinations.

The process of defining props for a button component, including variants, modifiers, size, and Boolean properties.

The extensive class name generation process in Tailwind and the resulting complexity when dealing with multiple variants.

CSS specificity and the importance of order in CSS files when using Tailwind to avoid unexpected styling.

The advantages of CVA in reducing the need for complex conditional statements and improving code readability.

The potential downside of creating unintended variants when using Tailwind's prop-based styling.

The importance of maintaining a consistent and predictable code structure when building design systems.

CVA's automatic generation of class names based on props, reducing the risk of typos and inconsistencies.

The use of compound variants in CVA to handle complex combinations of component properties.

The suggestion to improve CVA by allowing the definition of modifiers that can be either null or a specific value.

The recommendation to use CVA selectively for complex components within a design system, rather than for all components.

The potential for CVA to enhance maintainability and structure in large-scale component design within Tailwind.

A call to action for viewers to share their experiences with CVA and to support proposed improvements through community engagement.

Transcripts

play00:00

you know what I still find the most

play00:01

annoying thing about Tailwind the fact

play00:04

that you can really create a big mess

play00:05

when trying to Define all these class

play00:07

names especially if you have a component

play00:09

that has a lot of different variants of

play00:12

itself

play00:13

take for example a button a button that

play00:15

can either be a primary button or a

play00:18

secondary button maybe even a

play00:20

destructive button the button can be

play00:22

disabled maybe there's a variation in

play00:24

size you have a large button you have a

play00:26

smaller button all of these different

play00:28

props you pass into that button will

play00:31

change something in its class names

play00:33

and and don't get me wrong like it's

play00:35

it's not a problem of Tailwind because

play00:37

Tailwind gives you all the freedom in

play00:39

deciding how you build this

play00:41

but there actually lies a problem

play00:43

because it's so open you usually see

play00:45

that there is a lot of different

play00:46

approaches people take in this and

play00:48

sometimes even in one project

play00:51

and that usually results in quite a big

play00:53

mess as soon as you have a more

play00:55

complicated component

play00:57

so not that long ago when I was still

play00:59

styling all my components in CSS and JS

play01:01

I was actually using a library called

play01:03

stitches to also help in in styling

play01:07

these things in CSS and JS as well and

play01:09

if we look at their website you see how

play01:11

it works what you see here is that when

play01:14

creating a new component you actually

play01:15

Define an object called variants and in

play01:18

this object you can Nest different

play01:20

properties and each of these properties

play01:23

eventually will map to a property of

play01:25

your in this case react component as

play01:27

well so if you for example add a size

play01:31

property you see here

play01:33

by doing that you're actually defining

play01:35

different sizes this button can have and

play01:38

based on the value of the prop you pass

play01:40

in the actual CSS that's nested inside

play01:43

that object will get rendered so this

play01:45

gives you kind of a structure to Define

play01:47

what should change in the styles of a

play01:50

component when a certain prop gets

play01:52

passed in and there is one more thing

play01:54

that makes this even greater to use and

play01:57

stitches calls that compound variance

play02:00

because think about it what should

play02:01

happen if a primary button is also

play02:04

disabled let's say primary button is

play02:07

green should it then still be green or

play02:09

should it become grayish or a more toned

play02:12

down green color that that totally

play02:14

depends on design system of course but

play02:16

these combinations that are usually the

play02:19

cause of a lot of really weird if

play02:20

statements in your code to get the right

play02:22

code because the primary button should

play02:25

maybe a grayish green color but the

play02:28

secondary is perhaps a blue collar

play02:31

that's a bit grayish so there's all of

play02:33

these different variants in color and in

play02:35

styles that you need to Define

play02:37

and something like this hasn't been

play02:39

lacking in my opinion for for Tailwinds

play02:42

until recently when I discovered this

play02:44

Library called class variance Authority

play02:46

or CVA in short

play02:49

which does exactly this but for Tailwind

play02:51

if if we look at their examples on the

play02:54

GitHub page we see that they're doing

play02:56

something pretty similar to what

play02:58

stitches does it as well but they're

play03:01

instead of rendering Styles rendering

play03:03

different class names for Tailwind

play03:05

so what I want to do today is try to

play03:07

build a shopify's own button component

play03:10

from their design system and take in a

play03:12

few variants that they also offer in

play03:14

their design system like the primary

play03:15

button or a destructive button and see

play03:18

what the difference would be if we would

play03:19

build this in plain Tailwind or with CVA

play03:23

so let's jump right in and see if this

play03:26

can improve our workflow so while

play03:28

looking at shopify's button I noticed

play03:30

that for every different variant you

play03:32

select for example primary or

play03:35

destructive I noticed that they add in a

play03:37

different property to the component but

play03:39

also if you for example combine multiple

play03:41

they're always adding a different prop

play03:44

to the component this does actually

play03:46

bring one small downside and that is

play03:49

that you are able to create variants

play03:51

that aren't real variants

play03:54

you could for example make a primary

play03:56

destructive button which is probably not

play03:59

something they want to exist but if we

play04:01

go to 2D code sandbox page you see that

play04:04

we can actually add in

play04:05

primary and destructive and I will still

play04:09

render something albeit not a correct

play04:11

button probably

play04:12

so when trying to replicate this

play04:14

component I actually also changed a bit

play04:16

of the props around to try to make all

play04:19

these impossible variants impossible

play04:21

because most of the time that's actually

play04:23

a smart thing to do in design system

play04:25

make all these impossible variants

play04:27

impossible really weird variants of

play04:29

components and create things that should

play04:32

not exist

play04:33

so if we look at the code I already

play04:35

wrote as preparation you see that I

play04:37

actually added a few props to this

play04:39

button one is variance where you can

play04:41

pass in four different variants default

play04:43

primary destructive or monochrome a

play04:46

modifier which can make a button plain

play04:48

or outlined a size slim medium and large

play04:51

and two Boolean properties tool width

play04:55

and loading and you also can pass in a

play04:57

native button property called disabled

play04:59

which will also change something in the

play05:01

Styles so if we scroll down a little bit

play05:03

you see also that I added a few defaults

play05:05

if you do not pass any size then the

play05:07

size will become medium and the very end

play05:10

will become default and now we get

play05:11

actually to the Tailwind class name

play05:13

generation you see it's a lot but if we

play05:16

look on the left side you also see that

play05:19

there is actually a lot of different

play05:20

variants of this button as well there

play05:23

are smaller buttons bigger buttons

play05:25

outline buttons disabled buttons pinning

play05:27

buttons and that in four different

play05:29

variants as well so that that already

play05:31

makes it quite complicated it and then I

play05:34

actually even tried to to do my very

play05:36

best to make this as structured as

play05:39

possible but yeah you have to agree it's

play05:41

it's a lot so if we quickly look through

play05:43

this code you see that first I start

play05:46

with some general styles that are always

play05:47

applied which are actually not a lot

play05:51

um and then you see there's different

play05:52

variants which all set for example a

play05:55

background color a text color and a

play05:58

shadow for the default button next to

play06:01

that we have the modifiers either the

play06:03

outline which overrides the color to the

play06:06

current text color and does the same for

play06:08

the Shadow and for a destructive button

play06:10

that's outlined we changed the text

play06:12

color as well for the plane button we've

play06:15

also overwritten a few styles to remove

play06:18

a border and make padding a bit smaller

play06:20

and again for the destructive and

play06:23

primary button also change the text

play06:24

color and the same goes for different

play06:26

size of the button it's mainly attack

play06:28

size and padding change and for a

play06:30

disable button also changing the

play06:32

background color and the text color of

play06:34

the buttons

play06:35

so perhaps when someone talks you

play06:37

through this you're actually thinking

play06:39

well it's not too bad and it's true but

play06:42

also take into account that for example

play06:44

this does not include any hover or Focus

play06:46

States yet all of the buttons don't do

play06:49

anything when you hover them and perhaps

play06:51

there's even more complicated variants

play06:52

that you also want to combine

play06:55

and last but not least I knew about all

play06:57

the variants when creating this

play06:59

but imagine that there wasn't any

play07:02

outlined version of the button for

play07:04

example that could cause you to write

play07:05

Styles in a different way and then when

play07:08

you knew about it up front so next to it

play07:10

is quite tidy way of writing the class

play07:13

names I also created a different variant

play07:15

of the same button where you actually

play07:17

generate the class names in a slightly

play07:18

different way which is something you

play07:20

come across quite often but which I'm

play07:22

also not a huge fan of so if I go to

play07:25

this buttons not so neatly structured

play07:27

file you see that I'm taking a slightly

play07:30

different approach here I am creating a

play07:32

variable that contains all of the

play07:33

different class names that we want to

play07:35

render and later on I'm attaching them

play07:37

to the class name of the button itself

play07:40

so in here I'm actually doing a bit more

play07:42

complicated if statements but the entry

play07:45

result is actually the same but looking

play07:47

at this you already see that you need to

play07:49

take even more time to know what is

play07:51

actually doing and in my opinion that's

play07:53

mainly because they're not really

play07:55

grouped together by what a different

play07:57

variant of button should do how for

play07:59

example a primary button should look

play08:01

like but they are rather grouped by for

play08:03

example border or background color which

play08:06

is something that's irrelevant if you

play08:08

quickly want to scan how a component

play08:10

would behave in that case it's way

play08:12

easier to see the full picture of a

play08:15

certain variant instead of all of the

play08:17

different variants combined for a single

play08:19

property and exactly code like this is

play08:22

what I'm mostly worried about because

play08:24

this is kind of a bug waiting to happen

play08:26

because this is not really in my opinion

play08:29

something that's quickly maintainable

play08:31

people will easily make mistakes because

play08:33

you just simply Overlook something

play08:36

and if we quickly go back to the

play08:38

previous button there's also already a

play08:40

bug in this code as well and it maybe

play08:43

has a little bit to do with the way we

play08:45

wrote Our code but it's also something

play08:46

that's good to know when writing

play08:48

Tailwind because what you see here is

play08:51

that our plane button has a padding ax

play08:53

of 2 and a padding y of one whereas the

play08:56

different sizes also set their own

play08:59

padding so what is currently happening

play09:01

is that all these sailing classes are

play09:03

concatenated together into a long string

play09:05

so if we inspect this button you see

play09:08

that this button has both the smaller

play09:10

paddings from the playing class as well

play09:12

as the larger paddings from the large

play09:15

size and the reason that the largest

play09:18

padding is applied doesn't actually have

play09:20

anything to do with the order that the

play09:22

class names are defined because CSS

play09:25

completely ignores the order the class

play09:27

names are defined in the class attribute

play09:29

the only thing that takes precedence is

play09:31

the specificity of the CSS and in case

play09:33

of Tailwind as long as you don't do

play09:35

anything special all of the generic

play09:37

classes are of the same specificity so

play09:40

as soon as all of the classes are the

play09:42

same specificity what the browser will

play09:43

look at next is the order in which they

play09:46

got loaded in the CSS file so if one

play09:48

property comes after the next property

play09:50

in the CSS file and has the same

play09:52

specificity then that property will

play09:54

always be the one that's used so in this

play09:56

case the padding X of 6 is after the

play09:59

padding X of 2 in the file so that's why

play10:02

it's taking precedence so if we for

play10:04

example change this to adding X of 20

play10:06

you already see that it changes where

play10:09

it's still the first padding X that's

play10:11

defined but it's later in the file so in

play10:14

case you're using Tailwind is also

play10:15

really important to actually not Define

play10:17

duplicate properties because it might

play10:19

look like it works but perhaps it does

play10:22

not simply because there's different

play10:23

orders in the way the CSS is loaded and

play10:26

it could even be that because of hot

play10:28

reloading in the dev environment it

play10:31

actually seems to work but as soon as it

play10:32

gets built everything gets put in the

play10:34

correct order and then it will break in

play10:36

production so it's always good in these

play10:38

cases to also prevent defining duplicate

play10:41

properties as well so my advice in this

play10:43

case would be to copy the padding and

play10:46

add a different check where we check

play10:48

that the modifier is not equal to plane

play10:50

and the size equals slim and only then

play10:54

apply the different styles this way the

play10:56

padding will not get rendered if the

play10:58

variant is plain and then only this

play11:01

padding will be be applied

play11:03

so we now can do the exact same thing

play11:05

for the medium size and large size as

play11:07

well and with the help of copilot that

play11:10

seems to be pretty easy actually now we

play11:12

should not forget to remove the old

play11:14

pannings from the previous declarations

play11:16

and with that you already see that our

play11:19

button actually became smaller

play11:21

and there is no duplicate padding

play11:23

properties rendered anymore

play11:25

so and after we've looked how button

play11:27

would look with HUD CVA it's now time to

play11:30

convert it to CVA and see if the code

play11:32

becomes better in maintainability

play11:34

structure readability or perhaps not at

play11:38

all what I already did is create a new

play11:40

file called button CVA where I've only

play11:42

added in a basic button the next step we

play11:45

need to do of course is install class

play11:47

variants Authority by running yarn at

play11:50

Clause variance Authority

play11:53

and when we did that we are able to

play11:55

create a new button by creating a

play11:58

variable called button which equals CVA

play12:01

where we import CVA from class variance

play12:04

Authority

play12:05

and as a first parameter to this

play12:07

function we actually input all of the

play12:10

shared class names of the button

play12:12

and the second property of this function

play12:14

is an object that contains all the

play12:16

different variants

play12:18

the variants itself are nested inside an

play12:21

object called variants

play12:24

and if we look on the left side I

play12:26

actually decided to create a variant

play12:28

called variant to me it feels very

play12:31

natural to have a button that has a

play12:33

property variant called primary or

play12:36

secondary CVA itself usually uses the

play12:39

word intent for that so decide whatever

play12:41

suits you best but for now I will stick

play12:43

with variant and you can add any of

play12:46

these properties by just creating a new

play12:48

property inside the object and all of

play12:51

the keys that you write inside this

play12:52

object will become valid values for the

play12:55

button property so in our case that will

play12:58

be default primary destructive and

play13:02

monochrome and if we look at our code on

play13:04

the left side we can actually already

play13:06

copy in a few of these class names as

play13:08

well to set the correct styles

play13:11

monochrome primary and destructive what

play13:15

I also already did when setting this

play13:17

project up is also create this overview

play13:19

page where you can see all the buttons

play13:21

but next to the default button I also

play13:24

already added the placeholder for the

play13:25

CVA Button as well so if we go to the

play13:28

app.tsx you see that there's one section

play13:31

that has a default button and the second

play13:34

section that has the CVA button where I

play13:36

actually already render all of the

play13:38

different variants

play13:39

so what we can do now is instead of

play13:41

importing them from Button as well which

play13:43

I did as an initial setup actually

play13:46

imported the CVA variants from button

play13:48

CVA and what you will immediately see is

play13:51

that we are getting some type errors

play13:53

because right now we don't have any

play13:55

other types than children Define but

play13:57

that's something we will fix down the

play13:59

road

play13:59

so if we now go back to the preview page

play14:02

you see that there's no Styles applied

play14:04

yet and that is of course because right

play14:06

now we are only defining this object but

play14:09

not doing anything with it so what CVA

play14:12

does is this button is actually a

play14:15

function that you can set as a input for

play14:18

the class name so if we run this

play14:20

function it will return a class name

play14:23

String based on the different props of

play14:25

the button or actually not based on

play14:27

different props of the button but based

play14:30

on the arguments you pass in which

play14:31

should be the different props of the

play14:33

button so the next step in order to get

play14:35

that to work is to extract all the

play14:37

different props from the button and

play14:39

input them into that function and if we

play14:41

look at our default button we actually

play14:44

defined all of those manually however

play14:46

CVA gives us the option to do this

play14:49

automatically based on the object we

play14:51

defined here which is actually really

play14:53

neat because that way it's also

play14:55

impossible to create a typo for example

play14:57

and create a property that does not

play14:59

exist or is not used in CVA we can do so

play15:03

by actually extending our button props

play15:06

also from variant props where you pass

play15:10

in type of button and if we pass in this

play15:13

variant props type of button it will

play15:15

automatically add the variant prop to

play15:18

our button props type

play15:21

so this way we can extract the variant

play15:23

and already insert it into the button

play15:25

function so if we now go back to our

play15:27

button we see already that the colors

play15:29

are applied of course that's not

play15:31

everything but that's simply because we

play15:33

did not move over all of the different

play15:34

properties yet so let's do that next so

play15:37

to keep track of what we already copied

play15:40

in and what not I will actually add a

play15:42

comment in front of all the different

play15:44

things we moved over because the next

play15:46

step is actually the different modifiers

play15:48

so that means that we need to create a

play15:50

new modifier variant in here which can

play15:53

either have a value of outline and look

play15:56

at copilot already being this smart that

play15:58

it knows that I actually want to move

play15:59

the value from the left side over to the

play16:01

right side that's

play16:04

so let's just auto complete that and

play16:07

also add in the plane variant where we

play16:10

also copy these values over and then we

play16:13

comment in these two lines and for now

play16:15

we are actually leaving the destructive

play16:17

and primary outlines for a second

play16:19

because we're actually going to use

play16:20

compound variants down the road for this

play16:22

the next variant we of course have is

play16:25

size where we have slim which only has

play16:28

text M medium which is the same and

play16:32

large which has text base next up is a

play16:36

full width although instead of a string

play16:39

this is actually a Boolean but CVA also

play16:42

gives you the option to render a Boolean

play16:44

true or false in here

play16:46

and finally we do the same thing for

play16:48

disabled which also is a Boolean

play16:51

property for which we copy these values

play16:53

in and while we copied and disabled what

play16:56

happened down here is that an error

play16:58

popped up because it's actually

play16:59

complaining that there is already a

play17:01

property disabled in the button HTML

play17:04

attributes and that disabled property is

play17:06

actually different from the Boolean we

play17:09

set here because instead of a Boolean it

play17:11

can also be null or undefined in the

play17:14

default react types so since we only

play17:16

wanted to be a Boolean it's actually a

play17:19

good thing to let the variant props take

play17:21

precedence over what is in the button

play17:23

HTML props and we can do so by actually

play17:26

adding omits around the button HTML

play17:28

properties where we can omit the

play17:31

disabled property and if we do that the

play17:33

button props is happy again of course we

play17:35

should not forget to extract these

play17:37

modifier size full width and disabled

play17:41

variants from the props as well and pass

play17:43

them into the button function and as

play17:46

soon as we've done that we already see

play17:47

that we're a little bit closer to where

play17:49

we want to be the main things missing

play17:51

now are these compound variants so let's

play17:54

add those in next as a second property

play17:56

to the root object we can Define the

play17:59

compound variance which takes an array

play18:01

of different compound variants you want

play18:03

to apply specific societal so the first

play18:06

one you see which we skipped is the

play18:09

outline modifier and destructive variant

play18:11

we can style them by adding modifier

play18:13

outline and variant destructive and you

play18:17

see already that copilot is super smart

play18:19

again and knows that we want to add a

play18:22

class name text destructive to this and

play18:24

that's actually the only thing we need

play18:25

to do CVA is now smart enough to look at

play18:28

these different variants that we pass in

play18:30

and see if this class name should be

play18:33

applied as well because both of these

play18:36

variants are active we should do the

play18:38

same thing for the primary outline of

play18:40

course modifier outline variant primary

play18:43

and class name text primary and we also

play18:46

have some variants for the plane

play18:48

modifier that we want to set where

play18:50

modifier equals plane variance

play18:52

destructive and the text becomes text

play18:54

destructive again and the same thing for

play18:56

the primary variants that leaves two

play18:58

more which are firstly the paddings for

play19:00

the different buttons when the modifier

play19:02

plane is not applied so we can add them

play19:04

again by setting modifier to null first

play19:07

which means there is no modifier passed

play19:10

in and the size slim and the padding and

play19:13

the similar thing should also happen for

play19:15

the modifier outline and then we

play19:17

actually need to copy this object two

play19:19

more times to add in the medium size in

play19:23

the padding as well as the large size

play19:26

ice

play19:27

and what in my opinion would actually

play19:29

still be a really nice Improvement is If

play19:32

instead of defining multiple modifiers

play19:35

here where we need to say should be null

play19:37

or outline we could for example say to

play19:40

be either null or outline

play19:43

this way instead of creating two

play19:45

different compound variants we could

play19:47

only Define one or just say it should be

play19:50

not plain and by doing that it would

play19:52

make it way more organized and we would

play19:54

have a lot of less duplicate code which

play19:56

again makes this better maintainable and

play19:58

a lot easier and quicker to scan and if

play20:01

you do support that check out this pull

play20:03

request I created and give it an upfld

play20:05

as well because I think it's really

play20:06

useful and in my opinion it would make

play20:09

this tool even better so let's convince

play20:12

Joe together

play20:14

but all jokes aside let's for now remove

play20:17

this modifier again and add the outline

play20:20

in here and after we've done that

play20:22

there's only one compound variant left

play20:24

which is disabled true and variant

play20:27

default which should add a different

play20:29

border on there and finally we can add

play20:32

one more property which is default

play20:34

variance and inside default variants we

play20:36

can say that the variant should be

play20:39

default and the size should be medium

play20:41

this way we don't need to always specify

play20:43

the default variance to a button and

play20:46

these Styles would will get applied by

play20:48

default and as soon as we've done that

play20:50

saved it and go back to our components

play20:53

we see that we have all the variants

play20:56

back the only variant missing still is

play20:58

loading variant but if we look at the

play21:00

all buttons code you actually see that

play21:03

this does not add any class names to the

play21:06

component itself rather it manipulates a

play21:08

few child components so let's quickly

play21:10

copy that over as well since we can just

play21:12

replace all the children with this HTML

play21:15

and then we need to make sure that we

play21:17

add the loading Boolean in here and this

play21:20

loading Boolean should be added to the

play21:22

button props itself because it's not

play21:24

part of the CVA configuration since it

play21:26

does not add any Styles so we can just

play21:29

add it in here as a Boolean and then

play21:32

also destructure it from the props and

play21:35

by that we should have a loading button

play21:37

and look at that we do so as a quick

play21:41

summary it might be good to put these

play21:43

two side by side one more time so let me

play21:45

quickly uncomment the lines again and if

play21:48

we put them side by side you see that

play21:50

there's actually quite a bit of a

play21:51

difference

play21:52

because to me the CVA side looks quite a

play21:57

bit more structured

play21:58

whereas on the left side

play22:01

is pretty neat especially if you if you

play22:05

think about the not so neatly structured

play22:07

version I showed you before which is

play22:09

also still an alternative we should not

play22:11

forget because this is the type of code

play22:13

you see in production as well but it

play22:16

still feels that on the right side it's

play22:18

a lot quicker to see what different

play22:20

types of variants there are although on

play22:22

the left side you could of course also

play22:24

look at the interface

play22:25

but you need to scroll a lot up and down

play22:28

left and right to to really get a

play22:31

complete picture where with CVA you

play22:33

immediately see what different variants

play22:35

there are and what type of styles they

play22:37

apply the only downside right now is

play22:39

that you need to to Define quite a few

play22:40

of compound variants and especially

play22:43

quite a few duplicate compound variants

play22:45

to override class names whereas on the

play22:48

left side you can use a bit more

play22:50

JavaScript like does not equal for

play22:52

example which is not offered by TVA yet

play22:54

but I really hope they will implement

play22:57

this in the future because as soon as

play22:59

they do that that also ensures that

play23:01

these compound variants drop in half or

play23:03

maybe one third which in my opinion

play23:05

would make this a breeze to use and not

play23:07

per se because it's maybe a better

play23:09

overview but mostly also because it

play23:13

forces you to write your code in a

play23:15

certain way so that also means that

play23:17

everyone will write their Styles in this

play23:19

way I cannot add a little if statement

play23:21

somewhere in between and do something

play23:23

just a little bit different use a

play23:25

ternary if statement in in one place and

play23:27

maybe use a function to generate a class

play23:29

name because it's more complicated if

play23:31

you use CVA everyone will do it in the

play23:33

exact same way which makes your code way

play23:36

more predictable for for a developer to

play23:39

know where to find certain stuff and how

play23:40

things should work

play23:42

so in my opinion it definitely makes

play23:44

sense to use CVA for for bigger

play23:46

components especially within Design

play23:49

Systems where it's really important to

play23:51

create these tight boundaries and how

play23:53

components should work how they are

play23:55

structured and also to make sure that

play23:57

you don't break one of the five variants

play23:59

when you change something else what I'm

play24:01

definitely not recommending is creating

play24:03

all your components with CVA only use

play24:05

this tool when it makes sense if you're

play24:07

building a very huge design system or

play24:09

have a really really complicated

play24:10

component that has a lot of different

play24:13

variants within it CVA is not a library

play24:15

that's really big in file size so it's

play24:18

definitely something you can only use

play24:20

within a few components and that should

play24:22

as long as you're not building a full

play24:24

design system absolutely be the way you

play24:26

you're using this should not be the

play24:28

default for every component because that

play24:30

makes it just Overkill and takes away

play24:33

all of the benefits of Tailwind for

play24:35

quickly writing components and just

play24:37

iterating really quickly because you're

play24:39

adding a tool in between

play24:40

you should only edit when it makes sense

play24:43

and that is when you have a component

play24:45

that has a lot of different variants so

play24:47

I hope with this video I was able to

play24:49

show you how you can create better

play24:51

Design Systems within Tailwind as well

play24:53

without losing your mind with all the

play24:55

class names and ternary operators and

play24:57

everything that otherwise would be

play24:59

involved in this in my opinion CVA is

play25:02

really a blessing to use when you're

play25:04

building really big components so I hope

play25:07

you enjoyed this one and let me know if

play25:09

you've used it in production anywhere

play25:10

and what your experience is with it

play25:12

please subscribe leave a like down below

play25:15

and I'll see you in the next one

Rate This

5.0 / 5 (0 votes)

Ähnliche Tags
Tailwind CSSDesign SystemsClass VarianceCVAStylingReact ComponentsButton VariantsMaintainabilityCode StructureWeb Development
Benötigen Sie eine Zusammenfassung auf Englisch?