टेलविंड पहले हफ्ते तेज़ लगता है, और छठे महीने गड़बड़ हो जाता है अगर हर स्क्रीन यूटिलिटी का ढेर हो। जो टीमें इससे खुश रहती हैं उनके कुछ साझे रिवाज हैं: वे लेआउट सिस्टम बनाते हैं, पैटर्न दोहराए जाने पर कंपोनेंट निकालते हैं, डार्क मोड एक बार रूट पर जोड़ते हैं, और बिना ढांचे वाली अंतहीन क्लास स्ट्रिंग ठुकराते हैं।

यह शुरुआती ट्यूटोरियल नहीं है। माना जाता है कि आप पहले से टेलविंड इस्तेमाल करते हैं। लक्ष्य: ऐसा कोड जो तीसरे इंजीनियर के पीआर खोलने पर भी समझ आए।


क्लास सूप सीएसएस की नहीं, प्रक्रिया की समस्या है

"क्लास सूप" ऐसा दिखता है: एक ही div पर चालीस यूटिलिटी, तीन रूट पर लगभग एक जैसी तीन कार्ड, बिखरते स्पेसिंग नंबर (p-4 के पास p-5 के पास px-3.5), और हर पत्ते पर चिपकाए डार्क वेरिएंट, विरासत में नहीं।

सूप का मतलब अक्सर इनमें से एक होता है:

१. साझा लेआउट प्रिमिटिव नहीं। हर पेज ने मैक्स-विड्थ, गटर और वर्टिकल रिदम खुद गढ़ लिया। २. निकालने का नियम नहीं। वही बटन या पैनल दोबारा टाइप हुआ, कंपोनेंट नहीं बना। ३. डिज़ाइन टोकन डिफ़ॉल्ट से बाहर नहीं निकले। आर्बिट्रेरी वैल्यू (w-[347px], text-[#3a7]) सामान्य बन गईं। ४. डार्क मोड बाद की सोच रहा। हर एलिमेंट को अपना dark: जोड़ा, थीम सरफेस नहीं।

यूटिलिटी ठीक हैं। बेरोक-टोक कॉपी-पेस्ट ठीक नहीं। इलाज संरचना है, "बीईएम पर लौट जाओ" नहीं।


लेआउट सिस्टम: पेज शेल बार-बार न बनाएँ

कंपोनेंट से पहले पेज क्रोम बाँध लें। ज़्यादातर प्रोडक्ट को कुछ ही लेआउट टुकड़े चाहिए:

प्रिमिटिव काम आम यूटिलिटी
Container मैक्स विड्थ + क्षैतिज पैडिंग mx-auto w-full max-w-6xl px-4 sm:px-6
Stack लंबवत रिदम flex flex-col gap-4 (या नामित वेरिएंट में gap-6 / gap-8)
Cluster रैप वाली क्षैतिज पंक्ति flex flex-wrap items-center gap-2
Grid रिस्पॉन्सिव कॉलम grid gap-6 md:grid-cols-2 lg:grid-cols-3
Section सेक्शन की वर्टिकल पैडिंग py-12 md:py-16

रिएक्ट में उदाहरण (व्यू, स्वेल्ट या एंगुलर में वही विचार):

export function Container({
  children,
  className = "",
}: {
  children: React.ReactNode;
  className?: string;
}) {
  return (
    <div className={`mx-auto w-full max-w-6xl px-4 sm:px-6 ${className}`}>
      {children}
    </div>
  );
}

export function Stack({
  children,
  gap = "md",
  className = "",
}: {
  children: React.ReactNode;
  gap?: "sm" | "md" | "lg";
  className?: string;
}) {
  const gaps = { sm: "gap-2", md: "gap-4", lg: "gap-8" } as const;
  return (
    <div className={`flex flex-col ${gaps[gap]} ${className}`}>{children}</div>
  );
}

जो नियम टिकते हैं:

  • सामग्री के लिए एक मैक्स-विड्थ स्केल (max-w-3xl गद्य, max-w-6xl ऐप, फुल-ब्लीड केवल जान-बूझकर)।
  • छोटी सीढ़ी से स्पेसिंग (२ / ४ / ६ / ८ / १२), स्केल के हर नंबर नहीं।
  • गटर एक बार बढ़ें sm या md पर, फिर स्थिर रहें।
  • स्टैक में बच्चों पर मार्जिन से गैप बेहतर। गैप जोड़ता है; मार्जिन ढहता है और कंपोनेंट से भिड़ता है।

जो पेज सिर्फ Container + Stack + कार्डों की ग्रिड हो, वह मुक्त div पेड़ से रिव्यू में आसान है।

सीएसएस ग्रिड और तार्किक संरचना से लेआउट

डैशबोर्ड शेल के लिए क्षेत्र एक बार लिखें:

<div class="min-h-screen grid grid-cols-1 lg:grid-cols-[16rem_1fr]">
  <aside class="border-r border-slate-200 bg-slate-50 dark:border-slate-800 dark:bg-slate-950">
    <!-- nav -->
  </aside>
  <div class="flex min-h-0 flex-col">
    <header class="border-b border-slate-200 px-4 py-3 dark:border-slate-800">
      <!-- top bar -->
    </header>
    <main class="flex-1 overflow-auto p-4 md:p-6">
      <!-- page content -->
    </main>
  </div>
</div>

शेल की बॉर्डर और बैकग्राउंड शेल पर रखें। कार्ड और फ़ॉर्म कंपोनेंट पर छोड़ें। हर पेज में शेल क्रोम मिलाना वही रास्ता है जहाँ डार्क मोड और रिस्पॉन्सिव नेव एक रूट पर टूटते हैं, दूसरे पर नहीं।


कंपोनेंट निकालना: कब यूटिलिटी पेस्ट बंद करें

तब निकालें जब दो या ज़्यादा जगह संरचना और इरादा साझा करें, सिर्फ इसलिए नहीं कि दोनों पर flex है। अच्छे निकालन का नाम डिज़ाइनर पहचान ले: Button, Card, Field, Badge, Alert, Modal, EmptyState

वेरिएंट एपीआई निकालें, क्लासों का जंक ड्रॉअर नहीं

खराब पैटर्न: Button सिर्फ className ले, और हर कॉल साइट वेरिएंट फिर गढ़े:

// नाज़ुक: हर कॉल साइट बटन फिर गढ़ती है
<button className="rounded-lg bg-indigo-600 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-500">
  Save
</button>

बेहतर पैटर्न: छोटा वेरिएंट मैप (खुद या cva / tailwind-variants से):

const buttonVariants = {
  base: "inline-flex items-center justify-center rounded-lg text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 disabled:pointer-events-none disabled:opacity-50",
  variant: {
    primary: "bg-indigo-600 text-white hover:bg-indigo-500",
    secondary: "bg-slate-100 text-slate-900 hover:bg-slate-200 dark:bg-slate-800 dark:text-slate-100 dark:hover:bg-slate-700",
    ghost: "bg-transparent text-slate-700 hover:bg-slate-100 dark:text-slate-200 dark:hover:bg-slate-800",
  },
  size: {
    sm: "h-8 px-3",
    md: "h-10 px-4",
    lg: "h-11 px-6",
  },
} as const;

type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
  variant?: keyof typeof buttonVariants.variant;
  size?: keyof typeof buttonVariants.size;
};

export function Button({
  variant = "primary",
  size = "md",
  className = "",
  ...props
}: ButtonProps) {
  return (
    <button
      className={`${buttonVariants.base} ${buttonVariants.variant[variant]} ${buttonVariants.size[size]} ${className}`}
      {...props}
    />
  );
}

कॉल साइट छोटी रहती हैं। डिज़ाइन रिव्यू एक फ़ाइल में होता है। ब्रांड रंग बदले तो मैप एक बार संपादित करें।

@apply औज़ार है, जीवनशैली नहीं

सीएसएस मॉड्यूल या कंपोनेंट लेयर में:

@layer components {
  .card {
    @apply rounded-xl border border-slate-200 bg-white p-6 shadow-sm dark:border-slate-800 dark:bg-slate-900;
  }
}

@apply उन स्थिर, दोहराई सतहों के लिए जहाँ हर कॉल पर पैरामीटर नहीं चाहिए। जब वेरिएंट मायने रखें तो प्रॉप्स वाले कंपोनेंट चुनें। टेलविंड को दूसरे बीईएम में न बदलें जहाँ हर क्लास विशाल @apply ढेर हो जिसे कोई ओवरराइड न कर सके।

className का निकास द्वार

प्रिमिटिव पर लेआउट ट्वीक के लिए className दें (className="mt-6 w-full")। कॉल साइट को बीस रंग यूटिलिटी फेंककर कंपोनेंट फिर रंगने न दें। नया लुक चाहिए तो वेरिएंट जोड़ें।


डिज़ाइन टोकन: स्केल आप पर हावी होने से पहले अपने कब्जे में लें

डिफ़ॉल्ट शुरुआती बिंदु हैं। प्रोडक्शन ऐप को अक्सर tailwind.config (तीसरा संस्करण) या @theme (चौथा संस्करण) में पतली टोकन परत चाहिए:

// tailwind.config.js (v3 style)
module.exports = {
  theme: {
    extend: {
      colors: {
        brand: {
          50: "#eef2ff",
          500: "#6366f1",
          600: "#4f46e5",
          700: "#4338ca",
        },
        surface: {
          DEFAULT: "#ffffff",
          muted: "#f8fafc",
          inverse: "#0f172a",
        },
      },
      borderRadius: {
        card: "0.75rem",
      },
      boxShadow: {
        card: "0 1px 2px 0 rgb(15 23 42 / 0.06)",
      },
      maxWidth: {
        content: "42rem",
        app: "72rem",
      },
    },
  },
};

फिर लिखें bg-brand-600, rounded-card, max-w-app। आर्बिट्रेरी वैल्यू रिव्यू में थोड़ी शर्मिंदगी महसूस करानी चाहिए: एक बार के मार्केटिंग हीरो के लिए ठीक, रोज़ के स्पेसिंग और ब्रांड रंग के लिए गलत।

अगर डिज़ाइन फिग्मा टोकन देता है, उन्हें एक बार थीम में मैप करें। जेएसएक्स में हमेशा हेक्स हाथ से न कॉपी करें।


बिना उथल-पुथल का डार्क मोड

एक रणनीति चुनें और दस्तावेज़ करें:

१. क्लास रणनीति (html पर class): यूज़र टॉगल और उन एसएसआर ऐप के लिए बेहतर जो पेंट से पहले कुकी या लोकल स्टोरेज से पसंद सेट करें। २. मीडिया रणनीति (prefers-color-scheme): बिना टॉगल वाली कंटेंट साइटों के लिए ठीक।

// v3
module.exports = {
  darkMode: "class",
  // ...
};

रूट सेटअप (संकल्पना):

<html class="h-full antialiased">
  <body class="min-h-full bg-white text-slate-900 dark:bg-slate-950 dark:text-slate-100">
    ...
  </body>
</html>

थीम सरफेस पत्ते-पत्ते dark: से बेहतर

अर्थपूर्ण सतहें चुनें:

// सतहें लाइट/डार्क संभालें; बच्चे टेक्स्ट रंग विरासत में लें
export function Card({ children, className = "" }: { children: React.ReactNode; className?: string }) {
  return (
    <div
      className={`rounded-card border border-slate-200 bg-white text-slate-900 shadow-card dark:border-slate-800 dark:bg-slate-900 dark:text-slate-100 ${className}`}
    >
      {children}
    </div>
  );
}

कार्ड के अंदर text-slate-600 dark:text-slate-300 तभी जहाँ कंट्रास्ट दूसरे पायदान माँगे। हर नेस्टेड div पर बैकग्राउंड दोबारा न लिखें।

काला/सफ़ेद से आगे थीम के लिए सीएसएस वेरिएबल टेलविंड से अच्छे मिलते हैं:

:root {
  --color-bg: 255 255 255;
  --color-fg: 15 23 42;
}
.dark {
  --color-bg: 2 6 23;
  --color-fg: 241 245 249;
}
// थीम रंग आरजीबी चैनल: ओपेसिटी मॉडिफ़ायर काम करें
colors: {
  canvas: "rgb(var(--color-bg) / <alpha-value>)",
  ink: "rgb(var(--color-fg) / <alpha-value>)",
}

फिर bg-canvas text-ink रूट क्लास से पलटते हैं। मल्टी-ब्रांड या मल्टी-थीम ऐप इसी तरह संभलते हैं।

गलत थीम की चमक से बचें

टॉगल हो तो पहली पेंट से पहले क्लास सेट करें (head में इनलाइन स्क्रिप्ट, या कुकी से सर्वर-रेंडर्ड क्लास)। हाइड्रेशन के बाद थीम पलटने वाला रिएक्ट useEffect डार्क मोड यूज़र को सफ़ेद चमक दिखाएगा। यह प्रोडक्ट बग है, टेलविंड का नहीं।

कंट्रास्ट एपीआई का हिस्सा है

bg-slate-900 पर text-slate-400 आँख से ठीक लगे और डब्ल्यूसीएजी में फेल हो। दोनों थीम में प्राथमिक टेक्स्ट, द्वितीयक टेक्स्ट, बॉर्डर और फ़ोकस रिंग जाँचें। फ़ोकस स्टाइल साझे वेरिएंट मैप में रखें ताकि कोई कस्टम कंट्रोल बिना रिंग के न भेजे।


वे आदतें जो यूटिलिटी पठनीय रखती हैं

क्लासों को स्थिर क्रम में बाँधें

एक क्रम चुनें और टिके रहें। आम क्रम:

१. लेआउट / डिस्प्ले (flex, grid, block) २. पोज़ीशन / आकार (relative, w-full, h-10) ३. स्पेसिंग (p-4, gap-2, m-0) ४. टाइपोग्राफ़ी ५. रंग / बैकग्राउंड / बॉर्डर ६. इफ़ेक्ट (shadow, transition) ७. इंटरैक्टिव (hover:, focus-visible:) ८. डार्क / रिस्पॉन्सिव वेरिएंट अंत में, या अपनी प्रॉपर्टी के साथ

प्रीटियर प्लगइन prettier-plugin-tailwindcss क्रम लागू करता है, रिव्यू शोर घटता है।

रिस्पॉन्सिव और स्टेट वेरिएंट कंपोनेंट पर, हर पत्ते पर नहीं

// बेहतर
<section className="grid gap-4 md:grid-cols-2">
  <Card />
  <Card />
</section>

// उसी ग्रिड काम के लिए हर कार्ड पर md: दोहराने से बचें

लंबी स्ट्रिंग तब तोड़ें जब कंपोनेंट अभी स्थानीय हो

अगर एक-बार का ब्लॉक लंबा है पर साझा कंपोनेंट लायक नहीं, वेरिएबल या clsx/cn हेल्पर से तोड़ें:

const panel = cn(
  "rounded-xl border border-slate-200 bg-white p-6",
  "dark:border-slate-800 dark:bg-slate-900",
  emphasized && "ring-2 ring-brand-500",
);

पठनीय मल्टी-लाइन तीन सौ अक्षर वाले एट्रिब्यूट से बेहतर।

हर जगह ! से कैस्केड से न लड़ें

दस जगह !flex और !p-0 का मतलब कंपोनेंट एपीआई गलत है या कोई पैरेंट ज़्यादा स्टाइल किया गया है। स्टाइल की मालिकी सुधारें। इंपॉर्टेंट मॉडिफ़ायर थर्ड-पार्टी निकास के लिए हैं, घर की स्टाइल के लिए नहीं।

कंटेंट और फ़ॉर्म के डिफ़ॉल्ट

लंबे मार्कडाउन/सीएमएस के लिए हर h2 और p हाथ से न सजाएँ; @tailwindcss/typography (prose) इस्तेमाल करें। लेबल + कंट्रोल + एरर के लिए साझा Field रखें। फ़ॉर्म वही जगह हैं जहाँ क्लास सूप सबसे तेज़ बढ़ता है।


प्रोडक्शन में स्कैन और सीएसएस आकार

टेलविंड उन्हीं क्लासों को निकालता है जो कंटेंट पथों में मिलें। प्रोडक्शन दर्द अक्सर यहाँ से आता है:

  • डायनामिक क्लास निर्माण जो स्कैनर नहीं देखता:
// खराब: bg-indigo-600 कभी पूरी स्ट्रिंग नहीं दिखता
const color = "indigo";
return <div className={`bg-${color}-600`} />;
// अच्छा: सोर्स में पूरी क्लास नाम
const colors = { indigo: "bg-indigo-600", rose: "bg-rose-600" } as const;
return <div className={colors.indigo} />;
  • मोनोरिपो पैकेज के लिए गायब कंटेंट ग्लोब (./packages/ui/src/**/*.{ts,tsx})।
  • विशाल सेफ़लिस्ट जो बेकार सीएसएस वापस लाती हैं। चौड़ी सेफ़लिस्ट रेगेक्स से बेहतर कोड में पूरी स्ट्रिंग।

डिज़ाइन सिस्टम पैकेज स्कैनर की कंटेंट कॉन्फ़िग के अंदर रखें। निजी यूआई लाइब्रेरी जिसे टेलविंड न देखे, वहीं "स्टाइल सिर्फ प्रोड में गायब" पैदा होता है।


व्यावहारिक निकालन चेकलिस्ट

जब पीआर सूप लगे, यह सूची चलाएँ:

१. यह पेज शेल है या कंटेंट? शेल लेआउट प्रिमिटिव में जाए। २. क्या नामित कंट्रोल पहले से है? उसे इस्तेमाल करें; ज़रूरत हो तो वेरिएंट बढ़ाएँ। ३. क्या स्पेसिंग और टाइप तय सीढ़ी से हैं? एक-बार की वैल्यू हटाएँ। ४. क्या रंग ब्रांड टोकन हैं या कच्ची पैलेट का शोर? ५. क्या डार्क मोड एक सरफेस संभालती है, या पत्तों पर १५ dark: जोड़े? ६. क्या दो पंक्ति का cn() बिना नई फ़ाइल के इस स्थानीय ब्लॉक को पठनीय बनाएगा? ७. क्या साझा कंपोनेंट सिर्फ इसी नहीं, अगली तीन कॉल साइट बचाएगा?

तीसरी कॉल साइट पर निकालें तो भी जीत है। हर flex gap-2 पर जल्दी एब्स्ट्रैक्शन उल्टी गलती है।


छह महीने बाद अच्छा टेलविंड कैसा दिखता है

  • लेआउट प्रिमिटिव (Container, Stack, ऐप शेल) उबाऊ और दोबारा इस्तेमाल होते हैं।
  • बटन, फ़ील्ड, कार्ड, अलर्ट की छोटी वेरिएंट एपीआई होती है।
  • थीम टोकन ब्रांड, सतह और रेडीस ढकते हैं; आर्बिट्रेरी वैल्यू दुर्लभ।
  • डार्क मोड रूट की चिंता है; कंपोनेंट ज़्यादातर विरासत लेते हैं।
  • क्लास स्ट्रिंग क्रमबद्ध, अक्सर मल्टी-लाइन, और कॉल साइट पर छोटी।
  • स्कैनर हर उस पैकेज को देखता है जो क्लास नाम निकालता है।

टेलविंड डिज़ाइन सिस्टम खत्म नहीं करता। वह हल्के डिज़ाइन सिस्टम को सस्ता बनाता है। प्रोडक्शन पैटर्न किसी भी यूआई स्टैक जैसा है: साझा संरचना, साफ़ वेरिएंट, जादुई नंबरों की जगह टोकन, और पेस्ट झूठ बोलना शुरू करे तो निकालने का अनुशासन।