Overview
The Drakk3 Portfolio uses Tailwind CSS v4, which introduces a new native configuration approach via the@tailwindcss/vite plugin. This is a significant departure from the traditional PostCSS-based setup.
Tailwind v4 is configured directly through CSS using the
@theme directive instead of a JavaScript config file. This project includes both for shadcn/ui compatibility.Tailwind v4 Native Configuration
Vite Plugin Setup
Tailwind v4 is configured as a Vite plugin inastro.config.mjs:14:
astro.config.mjs
- ✅ Native Vite plugin (no PostCSS)
- ✅ Faster build times
- ✅ Better integration with modern bundlers
- ✅ Simplified configuration
The @theme Directive
Tailwind v4 introduces the @theme directive for defining design tokens directly in CSS. This project uses it in src/styles/global.css:4:
src/styles/global.css
Understanding Theme Tokens
Color System
The project uses a dark-only zinc-based color scheme with semantic naming:Background Colors
--color-background: Main page background (near black)--color-card: Elevated surface color--color-secondary: Subtle background variant
Foreground Colors
--color-foreground: Primary text color (near white)--color-muted-foreground: Secondary text (muted gray)--color-accent-foreground: Accent text
Interactive Colors
--color-primary: Primary action color (white)--color-ring: Focus ring color--color-destructive: Error/danger states
UI Elements
--color-border: Border color--color-input: Input field backgrounds--color-accent: Accent backgrounds
Border Radius Tokens
Consistent border radii using thecalc() function:
src/styles/global.css:25
Animation Tokens
Custom animation definitions insrc/styles/global.css:30:
Difference from PostCSS-Based Tailwind
Traditional Tailwind v3 Setup
Old approach (v3)
Tailwind v4 Native Approach
New approach (v4)
src/styles/global.css
Comparison
| Feature | Tailwind v3 (PostCSS) | Tailwind v4 (Native) |
|---|---|---|
| Configuration | JavaScript (tailwind.config.js) | CSS (@theme directive) |
| Build tool | PostCSS plugin | Vite plugin |
| Setup complexity | Multiple config files | Single CSS file |
| Build speed | Slower (PostCSS overhead) | Faster (native Vite) |
| HMR | Good | Excellent |
| CSS custom properties | Optional | First-class |
Tailwind v4 is significantly faster because it bypasses PostCSS and integrates directly with Vite’s build pipeline.
Why tailwind.config.mjs Still Exists
This project includes both a @theme block and a tailwind.config.mjs file:
tailwind.config.mjs:2
Why Both Files?
How it works:-
@themedirective (inglobal.css) defines the actual color values: -
tailwind.config.mjsmaps those values to Tailwind utilities: -
shadcn/ui components reference the Tailwind utilities:
Source of Truth
The
@theme directive in src/styles/global.css is the single source of truth for design tokens. The tailwind.config.mjs file simply bridges those tokens to shadcn/ui.CSS Custom Properties Approach
HSL Variable Bridge
The project uses a clever approach to bridge Tailwind v4 tokens with shadcn/ui:src/styles/global.css:36
hsl()?
shadcn/ui components use hsl(var(--primary)) syntax, so the variables store just the HSL values (0 0% 100%) without the hsl() function wrapper.
Token Flow
How to Add New Theme Tokens
Real Examples from the Project
Contact Form Card
The Contact component uses theme tokens extensively:src/components/Contact.tsx:47
rounded-lg→--radius-lgborder-border→--color-borderbg-card→--color-card
Button Component
The shadcn Button uses primary color tokens:Example from ui/button.tsx
bg-primary→hsl(var(--primary))(fromtailwind.config.mjs)--primary→0 0% 100%(from:rootinglobal.css)- Final value →
hsl(0 0% 100%)(white)
Muted Text
src/components/Contact.tsx:33
text-muted-foreground → --color-muted-foreground → hsl(240 5% 65%)
Animation Keyframes
Custom animations are defined alongside theme tokens:src/styles/global.css:58
src/components/Contact.tsx:104):
Best Practices
Use Semantic Names
Name tokens by their purpose (
--color-primary) not their value (--color-white).Maintain Consistency
Keep
@theme, :root, and tailwind.config.mjs in sync when adding new tokens.Use HSL Format
HSL provides better color manipulation and opacity control than RGB.
Document Custom Tokens
Add comments explaining the purpose of custom animation or spacing tokens.
Common Issues
Issue: Tailwind classes not working
Solution: Ensure@import "tailwindcss"; is at the top of global.css:
src/styles/global.css:1
Issue: Custom colors not applying
Solution: Check all three locations:- ✅
@themedirective has the color - ✅
:roothas the HSL value (withouthsl()) - ✅
tailwind.config.mjsmaps the variable
Issue: Animation not working
Solution: Define both the@keyframes and the --animate-* token:
Next Steps
Architecture Overview
Learn about the overall project architecture
Astro + React Integration
Understand how Astro and React work together