Taming Tailwind
A Frontend Developer's Journey Through Design Tokens & Dark Mode
In this post, I walk through some of the surprisingly hard-won lessons I encountered while building a portfolio site using React, Next.js, and Tailwind CSS — including real examples where things broke, and how I fixed them.
Goal
Build an elegant, expressive, and accessible site with:
- Clean vertical navigation
- Rotated typography
- Dark/light theme switching
- Design tokens via
:root - Typographic flair and polish
1. When Tailwind Surprises You
Real-Life Problem
I wanted a simple left border to highlight the active vertical nav item:
<Link
href="/blog"
className="border-l-2 pl-2 text-black dark:text-white border-black dark:border-white"
>
BLOG
</Link>
What Went Wrong
In light mode, it rendered as a black box instead of a thin line.
In dark mode, it looked correct.
Backgrounds and paddings were colliding silently.
The Fix
I removed Tailwind’s border-* classes entirely and used inline styles:
<Link
href="/blog"
style={{
borderLeft: "2px solid",
borderColor: theme === "dark" ? "white" : "black",
}}
>
BLOG
</Link>
Later, I abstracted borderColor to a CSS variable: --border-active.
2. Dark Mode Tokens: Avoid dark :root
Real-Life Problem
I wrote:
.dark :root {
--foreground: #fefefe;
}
And it didn’t work at all.
The Fix
Use .dark directly:
:root {
--foreground: #111;
}
.dark {
--foreground: #fefefe;
}
When <html class="dark"> toggles, the override works as intended.
3. When Typography Leaks Downstream
Real-Life Problem
My project hover details (like tech stacks) looked scrunched and unreadable.
The parent <nav> used a huge custom class:
<nav className="text-display-title serif">
The Fix
Reset typography inside the hover child:
<div className="text-xs font-sans not-italic leading-snug tracking-normal text-foreground">
React · TypeScript · Tailwind
</div>
4. Put Design Tokens Where They Belong
What Worked
All tokens live in global.css:
:root {
--background: #1e1b2e;
--foreground: #f6f1e7;
}
.dark {
--background: #0c0c0c;
--foreground: #fefefe;
}
Then map them into Tailwind:
colors: {
background: 'var(--background)',
foreground: 'var(--foreground)',
}
This made dark mode, theming, and visual consistency simple and reliable.
🧹 Final Thoughts
Tailwind isn’t stubborn; it just asks you to understand where its abstractions end.
In those boundary zones — between utilities, raw CSS, and design tokens — you can craft something both expressive and resilient.
Code that breathes a little easier.