Why cn() exists: conflicting classes and tailwind-merge
The naive button has both bg-teal-600 and bg-rose-600; the rule that comes later in the stylesheet wins, so the override is ignored and the button stays teal. cn removed the base bg-teal-600 and px-4, so the caller's classes apply. The last line shows that text-sm (a size) and text-rose-600 (a colour) don't conflict.
Tailwind is a CSS framework of small single-purpose classes (px-4, bg-teal-600, hover:bg-teal-700) that you combine in className; a build step generates only the classes you use, and a cn() helper merges conditional and conflicting classes.
Change the code and press Run (Ctrl+Enter). Predict what will happen first, then break it on purpose and read what changes. Your edits are saved and match the lesson page.
Ready for more? This phase has 5 hands-on exercises with automatic checks.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Write an Alert component with a tone prop (info, success, danger) that uses complete Tailwind class names from a lookup object, and accepts a className that can override them.
Make a disclosure (a button that shows and hides a panel) where the panel's visibility is styled with a data-state attribute and Tailwind's data-[state=open]: variant.
Explain it without notes
How does Tailwind decide which CSS to generate, and what does that mean for building class names dynamically?
What are variants? Show how React state can drive Tailwind styles through attributes.
Why do Tailwind projects use a cn() helper? What do clsx and tailwind-merge each do?
Why is extracting a component preferred over @apply?
Preview
Console
Nothing logged yet.Expected console output
Naive: rounded-md bg-teal-600 px-4 py-2 font-medium text-white bg-rose-600 px-6
background: rgb(13, 148, 136)
With cn: rounded-md py-2 font-medium text-white bg-rose-600 px-6
background: rgb(225, 29, 72)
text-sm text-rose-600