Tailwind CSS in Production · Theming and Consistency
Fourteen Shades of Blue
A year of arbitrary values left the product with fourteen different blues, five border radii and spacing that never quite lined up.
Scenario
Example team: five teams build features on one product. When a design calls for "our blue", developers copy the hex code from the design file into arbitrary values: bg-[#1d4ed8], text-[#1e40af], bg-[#2563eb]…
What you see in production
A rebrand needs a new primary colour. Search finds fourteen slightly different blues and dozens of one-off sizes. The rebrand estimate grows from a day to a month.
The naive code
<button class="bg-[#2563eb] rounded-[7px] px-[18px] py-[9px]">Save</button>
<a class="text-[#1d4ed8] hover:text-[#1e3a8a]">Details</a>
Reproduce it
Counting arbitrary values in a codebase shows the drift:
import re
from collections import Counter
templates = """
<button class="bg-[#2563eb] rounded-[7px] px-[18px]">Save</button>
<a class="text-[#1d4ed8] hover:text-[#1e3a8a]">Details</a>
<div class="border-[#2563ea] rounded-[8px]">Card</div>
<button class="bg-[#2564eb] rounded-[6px] px-[16px]">Send</button>
<span class="text-[#1d4ed8]">Note</span>
"""
values = Counter(re.findall(r"\[(#[0-9a-f]{6}|\d+px)\]", templates))
colors = {v: n for v, n in values.items() if v.startswith("#")}
sizes = {v: n for v, n in values.items() if v.endswith("px")}
print(f"{len(colors)} different colours:", colors)
print(f"{len(sizes)} different pixel sizes:", sizes)
Output
5 different colours: {'#2563eb': 1, '#1d4ed8': 2, '#1e3a8a': 1, '#2563ea': 1, '#2564eb': 1}
5 different pixel sizes: {'7px': 1, '18px': 1, '8px': 1, '6px': 1, '16px': 1}Root cause
Arbitrary values bypass the design system. Each one is a decision made in isolation, so near-duplicates accumulate and nothing can be changed centrally.
The fix
Define tokens once in @theme, named by purpose, and use them everywhere:
<style type="text/tailwindcss">
@theme {
--color-primary: oklch(0.55 0.22 263);
--color-primary-hover: oklch(0.48 0.22 263);
--radius-control: 0.5rem;
}
</style>
<div class="flex gap-3 p-6">
<button class="rounded-control bg-primary px-4 py-2 text-white hover:bg-primary-hover">Save</button>
<a href="#" class="rounded-control px-4 py-2 text-primary hover:text-primary-hover">Details</a>
</div>
Add a lint rule or CI check that flags new arbitrary colours, and review exceptions.
Trade-offs
- Tokens take design and engineering agreement up front, but every later change becomes one line.
- Arbitrary values are still fine for genuinely one-off layout values (
grid-cols-[14rem_1fr]).
Detect it in production
- A periodic report of arbitrary values per category (colours, radii, spacing).
- Visual audits of buttons and links across pages.
Key points
- Arbitrary values are an escape hatch, not a design system.
- Put brand decisions in
@themetokens with semantic names. - Measure drift and stop it in CI.
Practice questions
How do you keep colours and spacing consistent across a large Tailwind codebase?
Answer
Define design tokens in @theme (semantic colours, radii, fonts), use only those utilities, restrict arbitrary values with lint rules or CI checks, and share components for common UI so styles live in one place.
Open in the app to mark lessons complete, take notes and track your progress.