Tailwind CSS v4-এ Design Tokens — Modern CSS দিয়ে Production-Ready System বানান
Tailwind v4-এ design tokens এর নতুন approach। @theme directive, CSS variables, এবং কীভাবে একটা scalable design system বানাবেন — সম্পূর্ণ গাইড।
Tailwind CSS v3-এ একটা design token define করতে হলে tailwind.config.js ফাইল খুলতে হতো, JavaScript object-এ value লিখতে হতো, তারপর CSS-এ সেটা use করতে হতো। দুই জায়গায় দুই language-এ কাজ একটু awkward।
কিন্তু Tailwind v4 সব কিছু পাল্টে দিয়েছে। এখন design tokens সরাসরি CSS-এ লেখা যায়, native CSS variable-এর মতো। JavaScript config ফাইল পুরোপুরি optional
আজকের পোস্টে দেখব:
- Design tokens আসলে কী এবং কেন দরকার
- Tailwind v4-এর নতুন @theme directive
- কীভাবে একটা সম্পূর্ণ design system বানাবেন
- Dark mode, custom colors, typography সব
- যে ভুলগুলো এড়াতে হবে
Design Tokens আসলে কী?
ধরুন আপনার একটা website আছে। সেখানে button-এর background blue, link blue, focus ring blue — সব জায়গায় একই blue ব্যবহার করছেন। হঠাৎ ক্লায়েন্ট বললেন, "blue-টা একটু গাঢ় করো।" আপনি কোথায় কোথায় change করবেন? ৫০ জায়গায়? নাকি ১০০ জায়গায়?
Design tokens এই সমস্যাটাই solve করে। এটা হলো design decisions-এর নাম-যুক্ত variable — color, spacing, font-size, border-radius সব কিছু।
:root {
--color-primary: oklch(60% 0.18 250);
}
.button {
background: var(--color-primary);
}
.link {
color: var(--color-primary);
}
.ring {
box-shadow: 0 0 0 3px var(--color-primary);
}এখন blue change করতে চাইলে শুধু একটা line — --color-primary — পাল্টালেই সব জায়গায় update হবে।
Design tokens basically এটাই। কিন্তু Tailwind v4 এটাকে নিয়ে গেছে অন্য level-এ।
Tailwind v3 vs v4 — পার্থক্য
v3-এর পদ্ধতি (JavaScript config)
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
primary: "#3b82f6",
secondary: "#10b981",
},
spacing: {
section: "6rem",
},
},
},
};তারপর HTML-এ:
<div class="bg-primary p-section">Content</div>এই approach-এ সমস্যা ছিল:
- JavaScript ফাইলে CSS values লেখা — context switch
- Runtime-এ value access করা যেত না সহজে
- Custom CSS লিখতে গেলে
theme()function লাগত
v4-এর পদ্ধতি (CSS-first)
@import "tailwindcss";
@theme {
--color-primary: oklch(60% 0.18 250);
--color-secondary: oklch(70% 0.18 160);
--spacing-section: 6rem;
}ব্যস। আর কিছু না। এই tokens automatically:
- Utility classes generate করে —
bg-primary,p-sectionসব কাজ করে - CSS variables হিসেবে available —
var(--color-primary)সরাসরি use করতে পারেন - Type-safe — IDE autocomplete দেয়
@theme directive কীভাবে কাজ করে
@theme block-এ যা লেখেন সব CSS custom properties হিসেবে treat হয়। Naming convention খুব strict:
@theme {
/* Pattern: --<category>-<name> */
--color-brand: oklch(60% 0.2 250);
--font-display: "Instrument Serif", serif;
--spacing-gutter: 1.5rem;
--radius-pill: 9999px;
--shadow-card: 0 2px 8px rgb(0 0 0 / 0.08);
}প্রতিটা category-র জন্য Tailwind একটা utility prefix জানে:
@theme prefix | Utility class | কী generate হয় |
|---|---|---|
--color-* | bg-*, text-*, border-* | color utilities |
--font-* | font-* | font-family |
--text-* | text-* | font-size |
--spacing-* | p-*, m-*, gap-* | spacing |
--radius-* | rounded-* | border-radius |
--shadow-* | shadow-* | box-shadow |
--breakpoint-* | media queries | responsive |
--container-* | @container queries | container queries |
--animate-* | animate-* | animations |
--ease-* | ease-* | timing functions |
পূর্ণ design system বানানো — step by step
চলুন একটা real design system বানাই Notesaid24-এর মতো একটা blog platform-এর জন্য।
Step 1: Color system
@theme {
/* ─────────── Semantic colors (intent-based) ─────────── */
--color-background: oklch(98% 0.005 130);
--color-foreground: oklch(20% 0.02 130);
--color-muted: oklch(94% 0.01 130);
--color-muted-foreground: oklch(45% 0.02 130);
--color-border: oklch(88% 0.01 130);
/* ─────────── Brand colors ─────────── */
--color-primary: oklch(55% 0.16 145);
--color-primary-foreground: oklch(98% 0.005 130);
--color-accent: oklch(70% 0.15 60);
--color-accent-foreground: oklch(20% 0.02 130);
/* ─────────── Status colors ─────────── */
--color-success: oklch(60% 0.18 145);
--color-warning: oklch(70% 0.18 70);
--color-destructive: oklch(58% 0.22 25);
--color-info: oklch(60% 0.18 250);
}লক্ষ্য করুন:
- নামগুলো semantic (intent-based), color-based না —
primary,destructive,muted— কোন রঙ তা না বলে কী কাজ করবে সেটা বলছি - সব color OKLCH-এ — same lightness, predictable
- প্রতিটা color-এর সাথে একটা foreground pair (টেক্সট color)
এই pattern-এ button লেখা super simple:
<button class="bg-primary text-primary-foreground">Submit</button>
<button class="bg-destructive text-primary-foreground">Delete</button>Step 2: Typography system
@theme {
/* ─────────── Font families ─────────── */
--font-sans: "Hind Siliguri", system-ui, sans-serif;
--font-serif: "Instrument Serif", Georgia, serif;
--font-mono: "JetBrains Mono", ui-monospace, monospace;
/* ─────────── Font sizes with line-height ─────────── */
--text-xs: 0.75rem;
--text-xs--line-height: 1rem;
--text-sm: 0.875rem;
--text-sm--line-height: 1.25rem;
--text-base: 1rem;
--text-base--line-height: 1.6rem;
--text-lg: 1.125rem;
--text-lg--line-height: 1.75rem;
--text-xl: 1.375rem;
--text-xl--line-height: 1.9rem;
--text-display: 4rem;
--text-display--line-height: 1.05;
--text-display--letter-spacing: -0.02em;
}দারুণ feature: একই token-এর সাথে line-height এবং letter-spacing bundled করা যায় --*--line-height syntax দিয়ে। ব্যবহারের সময়:
<h1 class="text-display">Beautiful headlines</h1>
<!-- font-size, line-height, letter-spacing সব auto-apply -->Step 3: Spacing scale
@theme {
/* ─────────── Custom spacing (Tailwind defaults এর পাশাপাশি) ─────────── */
--spacing-section: 5rem;
--spacing-section-lg: 8rem;
--spacing-gutter: 1.5rem;
--spacing-stack: 1rem;
}ব্যবহার:
<section class="py-section">
<div class="space-y-stack">...</div>
</section>Step 4: Border radius
@theme {
--radius-card: 1rem;
--radius-button: 0.625rem;
--radius-pill: 9999px;
--radius-input: 0.5rem;
}ব্যবহার:
<div class="rounded-card">...</div>
<button class="rounded-button">Click</button>Step 5: Shadows
@theme {
--shadow-soft: 0 2px 8px rgb(0 0 0 / 0.04);
--shadow-card: 0 4px 16px rgb(0 0 0 / 0.06);
--shadow-elevated: 0 10px 40px rgb(0 0 0 / 0.1);
}ব্যবহার:
<div class="shadow-card hover:shadow-elevated">...</div>Dark mode কীভাবে handle করবেন
Tailwind v4-এ dark mode অসম্ভব simple। আপনার token-গুলোকে শর্ত অনুযায়ী override করতে হবে।
@import "tailwindcss";
/* ─────────── Light mode tokens ─────────── */
@theme {
--color-background: oklch(98% 0.005 130);
--color-foreground: oklch(20% 0.02 130);
--color-card: oklch(100% 0 0);
--color-border: oklch(88% 0.01 130);
}
/* ─────────── Dark mode override ─────────── */
@layer base {
.dark {
--color-background: oklch(15% 0.015 130);
--color-foreground: oklch(95% 0.005 130);
--color-card: oklch(20% 0.015 130);
--color-border: oklch(28% 0.015 130);
}
}এখন HTML-এ class="dark" যোগ করলেই (root-এ বা body-তে) সব color automatically flip হয়ে যাবে। আপনি কোথাও dark:bg-* লিখতে হবে না।
পুরো site-এ dark mode toggle করতে:
// next-themes বা manual
document.documentElement.classList.toggle("dark");CSS variables হিসেবে token access
@theme-এ লেখা সব token automatically CSS variables হিসেবে available:
.custom-component {
/* Direct variable access */
background: var(--color-primary);
font-family: var(--font-serif);
padding: var(--spacing-section);
}মানে যে কোনো custom CSS লিখলেও design system-এর সাথে synced থাকে। Token পাল্টালে এই custom CSS-ও পাল্টাবে।
Component-level token
প্রায়ই আপনি specific component-এর জন্য নিজস্ব token চান। এটা @theme-এ রাখা ঠিক না — কারণ utility class generate হবে অযথা। এর বদলে CSS variables ব্যবহার করুন:
.button {
--button-padding-x: 1.25rem;
--button-padding-y: 0.625rem;
padding: var(--button-padding-y) var(--button-padding-x);
background: var(--color-primary);
}
.button--large {
--button-padding-x: 1.75rem;
--button-padding-y: 0.875rem;
}এই pattern-এ:
- Global tokens (
--color-primary)@theme-এ - Component-specific tokens (
--button-padding-x) component-এ
দুই level-এ আলাদা responsibility।
Custom variant — keep utilities working
কখনো কখনো আপনি একটা নতুন utility variant চান — যেমন একটা category-specific theme। Tailwind v4-এ @custom-variant দিয়ে এটা সহজ:
@import "tailwindcss";
@custom-variant theme-blue (.theme-blue &);
@custom-variant theme-emerald (.theme-emerald &);ব্যবহার:
<div class="theme-blue">
<button class="theme-blue:bg-blue-500">Blue Theme</button>
</div>
<div class="theme-emerald">
<button class="theme-emerald:bg-emerald-500">Emerald Theme</button>
</div>এক HTML root class পাল্টালে নিচের সব button-এর theme পাল্টায়।
Animation tokens
Animation-ও tokens হিসেবে define করা যায়:
@theme {
--animate-fade-in: fade-in 0.4s ease-out;
--animate-slide-up: slide-up 0.5s ease-out;
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slide-up {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}ব্যবহার:
<div class="animate-fade-in">I fade in</div>
<div class="animate-slide-up">I slide up</div>Breakpoint token
Responsive breakpoint-ও design system-এর অংশ:
@theme {
--breakpoint-xs: 30rem; /* 480px */
--breakpoint-3xl: 100rem; /* 1600px */
}ব্যবহার:
<div class="xs:flex 3xl:max-w-screen-xl">...</div>Tailwind-এর default breakpoints (sm, md, lg, xl, 2xl) তো আছেই, এর সাথে আপনার custom-গুলোও পাবেন।
Pattern: Layered design system
বড় project-এ design system multiple layer-এ organize করা যায়:
@import "tailwindcss";
/* ─────────── Layer 1: Primitive values ─────────── */
@theme {
--color-blue-500: oklch(60% 0.18 250);
--color-emerald-500: oklch(60% 0.18 160);
--color-red-500: oklch(60% 0.22 25);
}
/* ─────────── Layer 2: Semantic tokens (refer primitives) ─────────── */
@theme {
--color-primary: var(--color-emerald-500);
--color-info: var(--color-blue-500);
--color-danger: var(--color-red-500);
}এতে দুই level-এ flexibility:
- Primitive layer-এ raw color
- Semantic layer-এ "এই color কী কাজ করে"
ক্লায়েন্ট যদি বলেন "primary green এর বদলে blue করো", শুধু একটা reference পাল্টালেই হয়:
--color-primary: var(--color-blue-500); /* Was: emerald */বাকি সব auto-update।
যা ভুল হয় বেশিরভাগ developer-এর
ভুল ১: Color name semantic না রাখা
/* ❌ এড়িয়ে চলুন */
@theme {
--color-blue: #3b82f6;
--color-our-purple: #8b5cf6;
}
/* ✅ ভালো */
@theme {
--color-primary: oklch(60% 0.18 250);
--color-accent: oklch(70% 0.18 320);
}Semantic নামের সুবিধা: ভবিষ্যতে color পাল্টালে নামটা ভুল লাগবে না।
ভুল ২: সব কিছু @theme-এ রাখা
@theme-এ যত কিছু রাখবেন, তত বেশি utility class generate হবে। শুধু reusable, global values এখানে রাখুন। One-off values custom CSS-এই থাক।
/* ❌ এটা @theme-এ না */
@theme {
--spacing-modal-header: 1.375rem; /* শুধু modal-এ ব্যবহার */
}
/* ✅ Component CSS-এই */
.modal-header {
padding: 1.375rem;
}ভুল ৩: Dark mode override @theme-এ লেখা
/* ❌ কাজ করবে না */
@theme {
--color-background: white;
}
.dark {
@theme {
--color-background: black;
}
}@theme block global, conditional না। Override @layer base-এ:
/* ✅ সঠিক */
@layer base {
.dark {
--color-background: oklch(15% 0.01 130);
}
}ভুল ৪: Token-এর জন্য JavaScript config-এ ফেরা
Tailwind v4-এ JavaScript config still সম্ভব (backward compatibility), কিন্তু সাধারণত দরকার নেই। CSS-first approach simpler — এটাই preferred।
tailwind.config.js শুধু তখন দরকার যখন:
- Plugin (যেমন
@tailwindcss/typography) install করছেন - Custom variant programmatic logic-এ create করছেন
- Older codebase migrate করছেন
যেভাবে token system নকশা করবেন
নতুন project শুরু করার সময় এই sequence follow করুন:
Step 1: Color system define করুন (light + dark)
Step 2: Typography scale বানান (font families + sizes)
Step 3: Spacing scale fix করুন (consistent rhythm)
Step 4: Border radius + shadow define করুন
Step 5: এগুলো ব্যবহার করে কয়েকটা core component (button, card, input) বানান
Step 6: শুধু তখন full project শুরু করুন
এটা আপনার design সিদ্ধান্ত প্রথমেই lock করে দেয়। পরে inconsistency-র সাথে struggle করতে হয় না।
সম্পূর্ণ globals.css template
এই template টা copy করে নিতে পারেন — production-ready starting point:
@import "tailwindcss";
@theme {
/* Colors — Light mode */
--color-background: oklch(98% 0.005 130);
--color-foreground: oklch(20% 0.02 130);
--color-card: oklch(100% 0 0);
--color-card-foreground: oklch(20% 0.02 130);
--color-muted: oklch(94% 0.01 130);
--color-muted-foreground: oklch(45% 0.02 130);
--color-border: oklch(88% 0.01 130);
--color-input: oklch(94% 0.01 130);
--color-ring: oklch(55% 0.16 145);
--color-primary: oklch(55% 0.16 145);
--color-primary-foreground: oklch(98% 0.005 130);
--color-accent: oklch(95% 0.02 60);
--color-accent-foreground: oklch(20% 0.02 130);
--color-success: oklch(60% 0.18 145);
--color-warning: oklch(70% 0.18 70);
--color-destructive: oklch(58% 0.22 25);
--color-info: oklch(60% 0.18 250);
/* Typography */
--font-sans: "Hind Siliguri", system-ui, sans-serif;
--font-serif: "Instrument Serif", Georgia, serif;
--font-mono: "JetBrains Mono", ui-monospace, monospace;
/* Radii */
--radius-button: 0.625rem;
--radius-input: 0.5rem;
--radius-card: 1rem;
--radius-pill: 9999px;
/* Shadows */
--shadow-soft: 0 2px 8px rgb(0 0 0 / 0.04);
--shadow-card: 0 4px 16px rgb(0 0 0 / 0.06);
--shadow-elevated: 0 10px 40px rgb(0 0 0 / 0.1);
/* Custom spacing */
--spacing-section: 5rem;
--spacing-section-lg: 8rem;
/* Animations */
--animate-fade-in: fade-in 0.4s ease-out;
--animate-slide-up: slide-up 0.5s ease-out;
}
/* Dark mode override */
@layer base {
.dark {
--color-background: oklch(15% 0.015 130);
--color-foreground: oklch(95% 0.005 130);
--color-card: oklch(20% 0.015 130);
--color-muted: oklch(25% 0.015 130);
--color-muted-foreground: oklch(65% 0.015 130);
--color-border: oklch(28% 0.015 130);
--color-accent: oklch(28% 0.02 130);
}
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slide-up {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}সংক্ষেপে
- Design tokens = একটা design system-এর নাম-যুক্ত variable
- Tailwind v4-এ সব কিছু CSS-first — JavaScript config optional
@themedirective utility class + CSS variable দুটোই generate করে- Color, typography, spacing, radius, shadow — সব এক জায়গায়
- Semantic naming ব্যবহার করুন (
primary,destructive), color-based না - Dark mode = token override করা,
dark:*class-এর দরকার নেই - OKLCH + Tailwind v4 = perceptually uniform, easily tweakable colors
- Component-specific tokens local CSS variable হিসেবে রাখুন
- নতুন project-এ tokens আগে define করুন, পরে component বানান
Tailwind v4-এর এই CSS-first approach শুধু convenient না — এটা design system এবং code base-এর মধ্যে একটা দারুণ bridge তৈরি করেছে। Designer যা ভাবেন, developer সেটাই লেখেন।
আপনার পরের project-এ এই pattern try করুন। tailwind.config.js-এর সাথে গতবারের struggle আর মনে থাকবে না।
Written by
Ahshan Habib
Full-stack developer. লেখেন TypeScript, CSS, এবং web design নিয়ে।
@AhshanHabibKeep reading
OKLCH Color কী? RGB ও HSL ছেড়ে কেন এই নতুন color format ব্যবহার করবেন
OKLCH হলো CSS-এর সবচেয়ে আধুনিক color format। কেন Tailwind v4, Radix, এবং modern design system এটা ব্যবহার করছে — সব বুঝবেন এই গাইডে।
Dark Mode Strategy ২০২৬ — Modern Web App এ Theming এর সম্পূর্ণ গাইড
FOUC এড়িয়ে, system preference detect করে, এবং performance বজায় রেখে কীভাবে production-grade dark mode বানাবেন — Next.js, Tailwind v4, CSS variables দিয়ে।