Skip to content

The Card That Stopped Decorating Itself

Adityo Guni Waluyo

Matching a card style turned out to be about deleting decoration and borrowing one shared divider class, not stacking more utilities.

TL;DR

Chasing a calmer card style, the author almost copied utility classes by hand until discovering the clean card used one shared class, reference-divider. The fix was mostly deleting borders, shadows, decorations, and an index prop, keeping only focus-visible and motion-reduce for accessibility. Lesson: prefer shared styles and divide-x/divide-y over duplicated decoration.

It was 10 PM, and my monitor was still blazing. I had just finished matching the Office card style with the Corporate Network card at the top of the page. But as I scrolled down, the service cards in services-grid.tsx still looked incredibly noisy. They had full borders, shadows, and a large watermark number in the top right corner. My first instinct? Copy the utility classes one by one, exactly like I had just done.

I initially thought that to match the appearance, I needed to add the same properties. Add border-l, add ring, resize the icon tiles. I had even started typing those classes. But when I peeked at the Corporate Network card code, which already looked calm and neat, I realized something was off. That card didn't have a stack of border or shadow utility classes. It just had one magic class: reference-divider.

Turns out, the key to matching the look wasn't adding, but removing. Almost the entire commit diff for this change was deletions. I threw away the full border, shadow-sm, the hover lift effect, and three absolute decorative elements that had been adorning the card: a hairline accent on top, a blurry subtle circle in the corner, and a large watermark index number. The index prop, which was only used to display that number, got deleted too.

// Before: full of decoration and the index prop
<div className="rounded-2xl border border-border bg-card shadow-sm hover:-translate-y-1.5 hover:shadow-xl">
// After: clean, referencing the shared class
<div className="reference-divider theme-transition bg-transparent min-h-full hover:-translate-y-1 hover:bg-card/60">

Why is this approach much more sensible? Because one class means one source of truth. Instead of duplicating decoration logic across every component, I can just reference the class defined once in the global stylesheet. I also downsized the icon tiles so they look calmer and do not compete for attention with the text content. What I deliberately kept was the focus-visible outline and motion-reduce:transform-none. This is an important accessibility contract, ensuring users who enable reduced motion mode on their devices are not forced to watch unnecessary animations [1].

There are limits, of course. Sometimes we genuinely need dividers between elements. If the goal is to create a separator line between sibling elements, the right tool is actually divide-x or divide-y, not manually sticking a left border [2]. Besides, using a class name that conceptually represents a divider is safer than forcing a physical left or right border, because logical properties like start and end will adapt much more easily if our site ever supports right-to-left writing modes [3].

I now have a new rule for myself. If tomorrow another card needs its style adjusted to match existing components, I will not immediately open the utility documentation to search for what to add. I will measure the diff by how much code I can delete. Sometimes, the best consistency is born when we make a card that stops decorating itself.

Sources

[1] Tailwind CSS — Hover, focus, and other states

[2] Tailwind CSS — border-width

[3] MDN Web Docs — Basic concepts of logical properties and values

Related articles