Tailwind v4 flips the config paradigm: instead of a tailwind.config.js file, you define your tokens directly in CSS using the @theme directive. It feels more natural and keeps your design system co-located with your styles.
Here's how I built the dark theme for this portfolio.
Token Strategy
I started with four decisions:
- One background colour —
#0b0b0d(ink). Near-black, slightly blue-black. - One accent colour — plum. A purple that reads as confident without being garish.
- Three text levels — primary (
#f4f4f5), secondary (#a1a1aa), tertiary (#52525b) - Type scale — 11px to 72px in steps that map to readable hierarchies
@theme Config
@import "tailwindcss";
@theme {
/* Palette */
--color-ink: #0b0b0d;
--color-ink-2: #111114;
--color-ink-3: #18181c;
--color-plum-300: #c4b5fd;
--color-plum-500: #a78bfa;
--color-plum-700: #7c3aed;
--color-text: #f4f4f5;
--color-text-2: #a1a1aa;
--color-text-3: #52525b;
/* Type scale */
--text-11: 0.6875rem;
--text-12: 0.75rem;
--text-13: 0.8125rem;
--text-14: 0.875rem;
--text-15: 0.9375rem;
--text-16: 1rem;
--text-18: 1.125rem;
--text-22: 1.375rem;
--text-26: 1.625rem;
--text-32: 2rem;
--text-48: 3rem;
--text-72: 4.5rem;
/* Border radius */
--radius-chip: 9999px;
--radius-field: 0.375rem;
--radius-card: 0.75rem;
/* Fonts */
--font-display: 'Fraunces', serif;
--font-sans: 'Inter', system-ui, sans-serif;
--font-mono: 'JetBrains Mono', monospace;
}
Contrast Strategy
Dark themes are deceptively easy to fail WCAG on. Low contrast text is the most common accessibility issue on dark sites.
My rules:
text-textonbg-ink: 15:1 contrast — AAAtext-text-2onbg-ink: 6.4:1 — AAtext-text-3onbg-ink: 3.5:1 — AA large text only (used only for labels and metadata)- Interactive elements always
text-textortext-plum-300
The Plum Accent
Plum was chosen because it:
- Reads as technical/engineering (vs. a warm colour that feels marketing-y)
- Has enough saturation to create clear visual hierarchy without being garish
- Works in gradients (
plum-700→plum-300) for depth
For focus rings I use outline: 2px solid var(--color-plum-500) — visible on both dark backgrounds and plum elements.
Al Amin Ahamed
Senior software engineer & AI practitioner. Building things in Laravel, PHP, and TypeScript.
About me →← Older
WP-CLI Tips That Actually Save Time
Newer →
Building a WooCommerce Payment Gateway from Scratch
One email a month. No noise.
What I shipped, what I read, occasional deep dive. Unsubscribe anytime.