01. Extracting common classes
🐇 TL;DR
- We have a bunch of class repetition between the various “hardcoded” buttons
- Let’s start by extracting the common classes to all buttons!
🐢 Background
In this challenge, we’re going to work with a series of buttons. These buttons have multiple size
, shape
and impact
style variants.
Here’s what they look like:
Impact
Size
Shape
They’re currently implemented as “hardcoded” <button>
elements, for which a lot of Tailwind classes are repeated over and over.
Here’s what the markup looks like:
<!-- prettier-ignore -->
<button class="rounded-md bg-indigo-500 px-5 py-2 font-semibold text-white shadow-md hover:bg-indigo-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none">Bold</button>
<!-- prettier-ignore -->
<button class="rounded-md bg-indigo-100 px-5 py-2 font-semibold text-indigo-700 hover:bg-indigo-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 active:translate-y-px disabled:pointer-events-none disabled:opacity-50">Light</button>
<!-- prettier-ignore -->
<button class="rounded-md bg-transparent px-5 py-2 font-semibold text-indigo-700 hover:bg-indigo-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 active:translate-y-px disabled:pointer-events-none disabled:opacity-50">None</button>
<!-- prettier-ignore -->
<button class="rounded bg-indigo-500 px-7 py-2.5 text-lg font-semibold text-white shadow-md hover:bg-indigo-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none">Large</button>
<!-- prettier-ignore -->
<button class="rounded bg-indigo-500 px-5 py-2 font-semibold text-white shadow-md hover:bg-indigo-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none">Medium</button>
<!-- prettier-ignore -->
<button class="rounded bg-indigo-500 px-3 py-1 text-sm font-semibold text-white shadow-md hover:bg-indigo-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none">Small</button>
<!-- prettier-ignore -->
<button class="bg-indigo-500 px-5 py-2 font-semibold text-white shadow-md hover:bg-indigo-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none">Square</button>
<!-- prettier-ignore -->
<button class="rounded-md bg-indigo-500 px-5 py-2 font-semibold text-white shadow-md hover:bg-indigo-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none">Rounded</button>
<!-- prettier-ignore -->
<button class="rounded-full bg-indigo-500 px-5 py-2 font-semibold text-white shadow-md hover:bg-indigo-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none">Pill button</button>
That’s obviously not ideal
Instead of repeating the Tailwind classes on each button, we want to dynamically generate the right composition of Tailwind classes for any given variant combination.
Here’s how the Button
component will be used, to generate the same buttons as the example above:
// Impact
<Button impact="bold">Bold</Button>
<Button impact="light">Light</Button>
<Button impact="none">None</Button>
// Size
<Button size="large">Large</Button>
<Button size="medium">Medium</Button>
<Button size="small">Small</Button>
// Shape
<Button shape="square">Square</Button>
<Button shape="rounded">Rounded</Button>
<Button shape="pill">Pill button</Button>
A Just-in-Time friendly implementation
There are a few rules and gotchas around what you should and shouldn’t do when working with Tailwind’s Just-in-Time Engine, to make sure things work properly.
For example, you cannot construct dynamic classes like so:
<div class={`bg-${props.color}`}>
This will not work.
This page from the Tailwind CSS documentation website is very helpful to understand how the Just-in-Time engine works, and why certain rules apply.
Extracting common styles first
A good first step towards organising our multi-style component styling is to identify what classes are common to every single button variant, and store those in a variable.
Let’s do just that in our fist challenge!
🏆 Your first challenge 🏆
In the Gitpod workspace below:
-
Take a look at the
src/partials/hardcoded-buttons.astro
file -
Identify the set of Tailwind classes that is common to all button variants
-
In
src/components/button.tsx
, collect those common classes inside thebaseClasses
variable. -
Add the
baseClasses
to theclassName
attribute of theButton
component.
You’ll find more hints within the project.
✌️ Good luck!
Open in Gitpod →