Styling و UI Libraries در اکوسیستم React

React درباره ظاهر برنامه هیچ نظری ندارد: فقط className و style را به عنصر می‌دهد. در مثال‌های این دوره هم یا از style درون‌خطی استفاده کردیم یا کلاس‌ها را بدون توضیح نوشتیم. در یک پروژه واقعی، دو تصمیم جدا اما مرتبط لازم است: استایل‌ها را چگونه بنویسیم (رویکرد Styling) و آیا کامپوننت‌های آماده بگیریم (کتابخانه UI).

رویکردهای Styling

رویکرد ایده اصلی نکته کلیدی
CSS معمولی فایل CSS سراسری که import می‌شود ساده، اما نام کلاس‌ها سراسری‌اند و ممکن است با هم تداخل کنند
CSS Modules CSS محدود به یک فایل با نام کلاس تولیدی بدون تداخل، بدون کتابخانه اضافه
Utility-first (Tailwind) ترکیب کلاس‌های کوچک مستقیم در JSX سرعت نوشتن بالا، JSX شلوغ‌تر
CSS-in-JS نوشتن استایل داخل جاوااسکریپت نوع زمان‌اجرا یا بدون زمان‌اجرا؛ ارتباط مهم با Server Components
style درون‌خطی آبجکت جاوااسکریپتی روی یک عنصر مناسب مقدار پویا، اما بدون hover و media query

CSS Modules

همان‌طور که در درس ۲۵-۱ دیدیم، import یک فایل CSS در جاوااسکریپت را Build Tool مدیریت می‌کند. در CSS Modules، نام فایل با .module.css تمام می‌شود و ابزار برای هر کلاس یک نام یکتا می‌سازد:

jsx
import styles from "./Button.module.css";

function Button({ children }) {
  return <button className={styles.primary}>{children}</button>;
}

کلاس primary در این فایل، با کلاس هم‌نام در فایل دیگر تداخل نمی‌کند، چون نام نهایی هر دو متفاوت است.

Tailwind CSS

Tailwind یک رویکرد Utility-first است: به‌جای نوشتن CSS جدا، کلاس‌های کوچک و از پیش‌تعریف‌شده را در JSX ترکیب می‌کنید. نسخه ۴ (۲۰۲۵) پیکربندی را به فایل CSS برده و دیگر فایل tailwind.config.js برای شروع لازم نیست؛ راه‌اندازی پایه یک خط در CSS است:

css
@import "tailwindcss";
jsx
<button className="rounded bg-blue-600 px-4 py-2 text-white hover:bg-blue-700">
  ثبت
</button>

مزیت آن سرعت نوشتن و یکدستی طراحی است؛ هزینه‌اش JSX طولانی‌تر و لزوم یادگیری نام کلاس‌هاست. چون در زمان Build به یک فایل CSS معمولی تبدیل می‌شود و هیچ کدی در مرورگر استایل تولید نمی‌کند، با Server Components مشکلی ندارد.

CSS-in-JS: زمان‌اجرا یا بدون زمان‌اجرا

کتابخانه‌هایی مثل styled-components و Emotion استایل را هنگام رندر در مرورگر تولید و تزریق می‌کنند. به همین دلیل، همان‌طور که در درس ۲۳-۳ (useInsertionEffect) دیدیم، برای تزریق درست استایل به یک Hook مخصوص نیاز دارند. در Server Componentها، که اصلاً کدشان به مرورگر نمی‌رسد (درس ۲۴-۱)، جایی برای این تزریق نیست؛ پس این کتابخانه‌ها در Server Component باید داخل مرز "use client" استفاده شوند (درس ۲۴-۲). علاوه بر آن، styled-components از مارس ۲۰۲۵ در حالت نگه‌داری (Maintenance Mode) است: حذف نشده، ولی قابلیت جدید نمی‌گیرد. برای پروژه‌های جدید، معمولاً این ابزارها بررسی می‌شوند:

  • CSS Modules یا Tailwind، که اصلاً CSS-in-JS نیستند.
  • CSS-in-JS بدون زمان‌اجرا مثل vanilla-extract، Panda CSS و StyleX: استایل را در جاوااسکریپت می‌نویسید اما در زمان Build به CSS معمولی تبدیل می‌شود، پس مشکل Server Components پیش نمی‌آید.

این به معنای ممنوع بودن runtime CSS-in-JS نیست؛ برای برنامه‌های Client-only یا موارد نیازمند تم‌بندی کاملاً پویا هنوز گزینه معتبری است.

style درون‌خطی و متغیرهای CSS

آبجکت style نمی‌تواند :hover، media query یا شبه‌کلاس داشته باشد؛ پس برای کل استایل مناسب نیست. اما برای انتقال یک مقدار پویا از State به CSS، ترکیب آن با متغیرهای CSS الگوی تمیزی است: مقدار را با style به‌صورت متغیر می‌دهید و بقیه استایل در CSS یا Tailwind نوشته می‌شود.

کتابخانه‌های UI: سه دسته

  • کتابخانه‌های آماده و استایل‌دار: MUI، Ant Design، Chakra UI، Mantine. مجموعه کامل کامپوننت با ظاهر پیش‌فرض و سیستم تم. سریع‌ترین راه شروع، اما شخصی‌سازی عمیق ممکن است سخت‌تر باشد.
  • کتابخانه‌های Headless: Radix UI، React Aria، Headless UI، Base UI. رفتار و دسترس‌پذیری (مدیریت Focus، ARIA، رفتار صفحه‌کلید) را می‌دهند اما هیچ استایلی ندارند. این‌ها دقیقاً همان کارهایی هستند که در فصل ۱۸ دستی ساختیم (مثل Dropdown درس ۱۸-۶)، فقط آزموده‌شده.
  • shadcn/ui: نه یک بسته‌ای که نصب شود، بلکه مجموعه‌ای از کامپوننت‌ها که کدشان را در پروژه خودتان کپی می‌کنید و معمولاً روی یک کتابخانه Headless و Tailwind ساخته شده‌اند. کنترل کامل کد با شماست، و نگه‌داری آن هم.

چرا دسترس‌پذیری یک معیار انتخاب است

ساختن Modal، Dropdown، Tab یا Date Picker قابل‌دسترس به‌صورت دستی، همان‌طور که در فصل ۱۸ دیدیم، جزئیات زیادی دارد (Focus Trap، aria-expanded، کلید Escape). کتابخانه‌های UI یا Headless این جزئیات را از قبل پیاده‌سازی کرده‌اند. این یکی از بزرگ‌ترین دلایل منطقی برای استفاده از آن‌هاست، به‌جای نوشتن همه چیز از صفر.

معیارهای انتخاب

  • سطح شخصی‌سازی ظاهر: طراحی اختصاصی و پیچیده معمولاً با Headless یا shadcn/ui راحت‌تر است؛ ظاهر استاندارد و سریع، با کتابخانه استایل‌دار.
  • حجم بسته: هر کتابخانه به بسته مرورگر اضافه می‌کند؛ مثل فصل بیستم، اندازه واقعی را بسنجید.
  • سازگاری با Server Components: بسیاری از کامپوننت‌های تعاملی (که State و Effect دارند) باید در مرز "use client" باشند. مستندات کتابخانه را بررسی کنید.
  • وابستگی بلندمدت: همان هزینه‌ای که در درس ۱۶-۴ دیدیم؛ تغییر کتابخانه UI در میانه پروژه، بازنویسی گسترده می‌خواهد.

نکته‌ای برای رابط‌های راست‌به‌چپ (RTL)

برای برنامه فارسی، دو چیز مهم است. اول، به‌جای ویژگی‌های جهت‌دار (margin-left، padding-right) از ویژگی‌های منطقی CSS استفاده کنید، مثل margin-inline-start و padding-inline، که با تغییر جهت صفحه خودکار جابه‌جا می‌شوند. Tailwind هم کلاس‌های متناظر (مثل ms-4 و me-4) و نوع rtl: دارد. دوم، پشتیبانی RTL در کتابخانه‌های UI یکسان نیست؛ پیش از انتخاب، آن را در مستندات بررسی کنید.

مثال قابل اجرا

در این مثال، یک مقدار پویا (رنگ) با متغیر CSS به استایل داده شده، اندازه با یک ویژگی data- کنترل می‌شود، و از ویژگی منطقی padding-inline استفاده شده است. بدون هیچ کتابخانه‌ای کار می‌کند.

استایل پویا با متغیر CSS و ویژگی data
import { useState } from "react";

const css = `
.badge {
  padding-inline: 12px;
  padding-block: 6px;
  border-radius: 999px;
  color: white;
  background: var(--accent);
}
.badge[data-size="large"] {
  font-size: 1.25rem;
}
`;

function Badge({ color, size, children }) {
  return (
    <span className="badge" data-size={size} style={{ "--accent": color }}>
      {children}
    </span>
  );
}

function App() {
  const [large, setLarge] = useState(false);

  return (
    <div>
      <style>{css}</style>
      <Badge color="teal" size={large ? "large" : "small"}>
        برچسب
      </Badge>
      <button onClick={() => setLarge(!large)}>تغییر اندازه</button>
    </div>
  );
}
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

React رویکرد Styling را تعیین نمی‌کند. CSS Modules ساده و بدون تداخل است، Tailwind سرعت می‌دهد و با Server Components سازگار است، و CSS-in-JS زمان‌اجرا (مثل styled-components و Emotion) در Server Component به مرز "use client" نیاز دارد؛ styled-components از مارس ۲۰۲۵ در حالت نگه‌داری است و برای پروژه‌های جدید گزینه‌های بدون زمان‌اجرا یا CSS Modules و Tailwind بررسی می‌شوند. کتابخانه‌های UI در سه دسته آماده، Headless و کپی‌شونده (مثل shadcn/ui) قرار می‌گیرند و بخشی از ارزش آن‌ها، دسترس‌پذیری آزموده‌شده فصل ۱۸ است. برای برنامه فارسی، پشتیبانی RTL و ویژگی‌های منطقی CSS را هم در انتخاب لحاظ کنید. در درس بعدی، به State Management در اکوسیستم می‌پردازیم.