انتقل إلى المحتوى
TopClass UI

المكوّنات

46 مكوّنًا، لكل واحد عرض حيّ: كل الحالات معًا، ومساحة تجربة موصولة بالخصائص الحقيقية، وسطر الاستيراد.

قبل أن تبدأ

مرة واحدة لكل تطبيق

كل بطاقة أدناه تعرض سطر استيراد. هذه الخطوات الثلاث تجعله يعمل.

  1. 1. ثبّت الحزمة

    terminal
    npm i topclassui@beta zod

    ثلاث اعتماديات نظيرة: react وreact-dom وTailwind CSS 4.2 أو أحدث. مشروعك فيه هذه بالفعل، وzod يُثبَّت مع الحزمة.

  2. 2. مدخل Tailwind CSS v4

    app/globals.css
    @import "tailwindcss";
    @import "topclassui/tokens.css";
    @import "topclassui/styles.css";

    ثلاثة أسطر، بهذا الترتيب، وبلا tailwind.config.js. السطر الثالث يحمل الربط الذي يعطي Tailwind أسماء الأصناف الدلالية.

  3. 3. التخطيط الجذري

    app/[locale]/layout.tsx
    const dir = locale === 'ar' ? 'rtl' : 'ltr'
    
    return (
      <html lang={locale} dir={dir} data-theme="dark" suppressHydrationWarning>
        <head><ThemeScript /></head>
        <body>
          <TopClassProvider direction={dir} locale={locale}>
            {children}
          </TopClassProvider>
        </body>
      </html>
    )

    مرّر direction وlocale إلى TopClassProvider خاصيتين من التخطيط؛ ولا تقرأهما أبدًا من document.dir داخل effect. يأتي ThemeScript أولًا في <head>: يضبط data-theme قبل أول رسم.

كيف تقرأ البطاقة

كل مكوّن أدناه مرتّب بالطريقة نفسها، فتتعلمها مرة واحدة. خمسة أجزاء، من الأعلى إلى الأسفل.

  1. العرض

    المكوّن في أكثر إعداداته شيوعًا، على خلفية الصفحة، لتراه في سياقه.

  2. جرّبه

    كل خاصية يمكنك تغييرها، مع قيمها المسموح بها.

  3. الشيفرة

    شيفرة JSX التي تنتج العرض فوقها. انسخها والصقها فتعمل.

  4. كل الحالات

    التمرير والتركيز والتعطيل والتحميل والخطأ - كلها معًا. لا تحتاج إلى التمرير لمراجعة حالة.

  5. استورده

    سطر الاستيراد الواحد من الحزمة، وأمر التثبيت.

الإجراءات

4 مكوّنات

ما ينقر عليه المستخدم. كل واحد منها يُعرض على الخادم ما لم يحتج إلى معالج أحداث في المتصفح.

زر

server - 0 KB

خمسة أنماط عبر ست نبرات، يُعرض على الخادم بلا JavaScript. ومن خلال render يصبح رابطًا حقيقيًا بالشكل نفسه.

تثبيت

جرّبه

variant
tone
size
loading
fullWidth

الشيفرة

button.tsx
import { Button } from 'topclassui/button'

<Button>Save</Button>

loading يمنع النقر ويعلن عن نفسه عبر aria-busy، لكنه يحتفظ بلونه كاملًا فلا يبدو معطّلًا.

كل الحالات، بدون تمرير الفأرة

5 حالات

أو استورده من الحزمة

topclassui/button
import { Button } from 'topclassui/button'

ثبّت مرة واحدة:npm i topclassui@beta zod

وسم

split - الحجم لم يُقَس بعد

شريحة تسمية لموضوع، تُعرض على الخادم. تمرير onRemove يضيف زر إزالة، وهو الجزء الوحيد الذي يعمل في المتصفح.

تثبيت
Design systems

جرّبه

tone
size

الشيفرة

tag.tsx
import { Tag } from 'topclassui/tag'

<Tag>Design systems</Tag>

الوسم العادي يبقى على الخادم، وonRemove هو ما يضيف زر الإزالة، وإخراج الوسم من القائمة مسؤوليتك.

كل الحالات، بدون تمرير الفأرة

حالتان
PlainRemovable

أو استورده من الحزمة

topclassui/tag
import { Tag } from 'topclassui/tag'

ثبّت مرة واحدة:npm i topclassui@beta zod

مفتاح

server - 0 KB

غطاء مفتاح لمفتاح يضغطه القارئ، يُعرض على الخادم. والتركيبة مفاتيح متجاورة، بلا جزء تجميع وبلا علامة زائد.

تثبيت
KTabCtrlShiftEnterEsc

الشيفرة

kbd.tsx
import { Kbd } from 'topclassui/kbd'

export default function Demo() {
  return (
    <div className="flex flex-wrap items-center gap-3">
      <Kbd>K</Kbd>
      <Kbd>Tab</Kbd>
      <Kbd>Ctrl</Kbd>
      <Kbd>Shift</Kbd>
      <Kbd>Enter</Kbd>
      <Kbd>Esc</Kbd>
    </div>
  )
}

الأيقونة داخل المفتاح <Svg> بلا حجم: بقيمتها الافتراضية 1em تتبع نص المفتاح نفسه.

أو استورده من الحزمة

topclassui/kbd
import { Kbd } from 'topclassui/kbd'

ثبّت مرة واحدة:npm i topclassui@beta zod

تحكم مقسّم

client - الحجم لم يُقَس بعد

اختيار واحد من خيارين إلى خمسة خيارات قصيرة، مرسوم كمسار واحد. هو مجموعة أزرار راديو: الأسهم تختار أثناء التنقل، وتنعكس من اليمين إلى اليسار.

تثبيت

جرّبه

size
fullWidth
invalid

الشيفرة

segmented-control.tsx
import { SegmentedControlItem, SegmentedControlRoot } from 'topclassui/segmented-control'

<SegmentedControlRoot aria-label="View" defaultValue="board">
  <SegmentedControlItem value="board">Board</SegmentedControlItem>
  <SegmentedControlItem value="table">Table</SegmentedControlItem>
  <SegmentedControlItem value="calendar">Calendar</SegmentedControlItem>
</SegmentedControlRoot>

الأسهم تنقل وتختار معًا، وتحت TopClassProvider باتجاه من اليمين إلى اليسار ينتقل السهم الأيمن إلى المقطع السابق.

كل الحالات، بدون تمرير الفأرة

4 حالات

أو استورده من الحزمة

topclassui/segmented-control
import { SegmentedControlRoot, SegmentedControlItem } from 'topclassui/segmented-control'

ثبّت مرة واحدة:npm i topclassui@beta zod

النماذج

13 مكوّنًا

كل عنصر تحكم يحمل اسمًا حقيقيًا ويُرسَل داخل <form> عادي. يعمل Input وTextarea قبل تحميل أي JavaScript، والبقية ترسل قيمتها الافتراضية وتصبح تفاعلية بعد تحميله.

حقل نص

server - 0 KB

حقل إدخال أصلي يُعرض على الخادم ولا يشحن أي JavaScript. الأنواع ترفض حقلًا بلا اسم.

تثبيت

جرّبه

size
invalid
fullWidth

الشيفرة

input.tsx
import { Input } from 'topclassui/input'

<div className="grid max-w-sm gap-1">
  <label htmlFor="input-playground" className="text-sm font-medium text-body">Email</label>
  <Input id="input-playground" name="email" type="email" autoComplete="email" />
</div>

خارج Field يحتاج Input إلى id أو aria-label أو aria-labelledby: الأنواع ترفض حقلًا بلا تسمية.

كل الحالات، بدون تمرير الفأرة

6 حالات

أو استورده من الحزمة

topclassui/input
import { Input } from 'topclassui/input'

ثبّت مرة واحدة:npm i topclassui@beta zod

مربع نص متعدد الأسطر

split - الحجم لم يُقَس بعد

مربع نص أصلي يُعرض على الخادم. التمدد التلقائي والعدّاد الحي هما الجزآن الوحيدان اللذان يُحمَّلان في المتصفح.

تثبيت

جرّبه

size
invalid
fullWidth
rows
maxRows
autosize
showCount

الشيفرة

textarea.tsx
import { Textarea } from 'topclassui/textarea'

<div className="grid max-w-sm gap-1">
  <label htmlFor="textarea-playground" className="text-sm font-medium text-body">About you</label>
  <Textarea id="textarea-playground" name="bio" placeholder="Write a short paragraph" />
</div>

وحده هو HTML من الخادم؛ autosize أو showCount هو ما يحمّل نصف العميل الصغير.

كل الحالات، بدون تمرير الفأرة

6 حالات

أو استورده من الحزمة

topclassui/textarea
import { Textarea } from 'topclassui/textarea'

ثبّت مرة واحدة:npm i topclassui@beta zod

قائمة اختيار

client - الحجم لم يُقَس بعد

اختيار واحد من قائمة بيانات بسيطة. تبقى القائمة المنبثقة داخل الشاشة وتمرّر نفسها، بارتفاع سبعة صفوف افتراضيًا.

تثبيت

جرّبه

size
invalid
fullWidth
placement
visibleRows
loadMoreThreshold

الشيفرة

select.tsx
import { Select } from 'topclassui/select'

<div className="grid justify-items-start gap-1.5">
  <label htmlFor="select-playground" className="text-sm text-body">Country</label>
  <Select id="select-playground" items={COUNTRIES} defaultValue="jo" />
</div>

items بيانات بسيطة، فتستطيع صفحة خادم أن تعرض Select: لا تعبر أي دالة إلى المتصفح.

كل الحالات، بدون تمرير الفأرة

4 حالات
Pick a paid plan.

أو استورده من الحزمة

topclassui/select
import { Select } from 'topclassui/select'

ثبّت مرة واحدة:npm i topclassui@beta zod

قائمة اختيار مع بحث

client - الحجم لم يُقَس بعد

حقل نص يصفّي قائمة أثناء الكتابة. يعرض الصفوف الظاهرة فقط بعد 200 خيار، ويستدعي loadMore لجلب الصفحة التالية.

تثبيت

جرّبه

size
invalid
fullWidth
placement
visibleRows
hasMore
loadMoreThreshold
status

الشيفرة

combobox.tsx
import { Combobox } from 'topclassui/combobox'

<div className="grid justify-items-start gap-1">
  <label htmlFor="combobox-playground" className="text-sm font-medium text-body">Framework</label>
  <Combobox id="combobox-playground" items={FRAMEWORKS} placeholder="Search frameworks" />
</div>

تجري التصفية على الخيارات المحمّلة حتى الآن؛ وتصل الصفحة التالية عبر hasMore وloadMore.

كل الحالات، بدون تمرير الفأرة

4 حالات

أو استورده من الحزمة

topclassui/combobox
import { Combobox } from 'topclassui/combobox'

ثبّت مرة واحدة:npm i topclassui@beta zod

مربع اختيار

client - الحجم لم يُقَس بعد

محدد أو غير محدد أو مختلط. حقل مخفي يرسل القيمة الافتراضية قبل الترطيب، وإعادة ضبط النموذج تعيدها.

تثبيت

جرّبه

size
invalid

الشيفرة

checkbox.tsx
import { Checkbox } from 'topclassui/checkbox'

<div className="flex items-center gap-2">
  <Checkbox id="checkbox-playground" defaultChecked />
  <label htmlFor="checkbox-playground" className="text-sm text-body">I accept the terms</label>
</div>

المربع زر أصلي <button role="checkbox">، وبجانبه مربع اختيار مخفي هو ما يرسله النموذج.

كل الحالات، بدون تمرير الفأرة

9 حالات

أو استورده من الحزمة

topclassui/checkbox
import { Checkbox } from 'topclassui/checkbox'

ثبّت مرة واحدة:npm i topclassui@beta zod

مجموعة اختيار فردي

client - الحجم لم يُقَس بعد

اختيار واحد من خيارات قليلة معروضة كلها معًا. للمجموعة محطة Tab واحدة، والزر المحدد هو تلك المحطة قبل الترطيب.

تثبيت

جرّبه

size
orientation
invalid

الشيفرة

radio-group.tsx
import { RadioGroupItem, RadioGroupRoot } from 'topclassui/radio-group'

<div className="grid justify-items-start gap-2">
  <span id="radio-group-playground-label" className="text-sm text-body">Billing</span>
  <RadioGroupRoot aria-labelledby="radio-group-playground-label" defaultValue="yearly">
    <RadioGroupItem value="monthly">Monthly</RadioGroupItem>
    <RadioGroupItem value="yearly">Yearly</RadioGroupItem>
    <RadioGroupItem value="lifetime">Lifetime</RadioGroupItem>
  </RadioGroupRoot>
</div>

المجموعة تحمل الحالة والنموذج؛ وكل RadioGroupItem يحمل value الخاص به ونصه فقط.

كل الحالات، بدون تمرير الفأرة

4 حالات

أو استورده من الحزمة

topclassui/radio-group
import { RadioGroupRoot, RadioGroupItem } from 'topclassui/radio-group'

ثبّت مرة واحدة:npm i topclassui@beta zod

مفتاح تبديل

client - الحجم لم يُقَس بعد

مفتاح تشغيل وإطفاء لإعداد يسري فورًا. يتحرك مقبضه في الاتجاه الصحيح في التخطيطات من اليمين إلى اليسار.

تثبيت

جرّبه

size
invalid

الشيفرة

switch.tsx
import { Switch } from 'topclassui/switch'

<div className="flex items-center gap-2">
  <Switch id="switch-playground" defaultChecked />
  <label htmlFor="switch-playground" className="text-sm text-body">Weekly digest</label>
</div>

المفتاحان xs وsm يكبران إلى هدف بمقدار 44px تحت مؤشر لمس، فيبقى المقبض سهل اللمس.

كل الحالات، بدون تمرير الفأرة

7 حالات

أو استورده من الحزمة

topclassui/switch
import { Switch } from 'topclassui/switch'

ثبّت مرة واحدة:npm i topclassui@beta zod

شريط تمرير

client - الحجم لم يُقَس بعد

قيمة واحدة أو نطاق من قيمتين. مفاتيح الأسهم والضغط على المسار يصلان إلى النتيجة نفسها التي يصل إليها السحب.

تثبيت

جرّبه

size
invalid
fullWidth
showValue
min
max
step
largeStep
minStepsBetweenValues

الشيفرة

slider.tsx
import { Slider } from 'topclassui/slider'

<div className="grid justify-items-start gap-2">
  <span id="slider-playground-label" className="text-sm text-body">Volume</span>
  <Slider aria-labelledby="slider-playground-label" defaultValue={60} />
</div>

حقل نطاق مخفي يحمل القيمة، فيُرسل الشريط مع نموذجه؛ ويتحرك المقبض بعد ترطيب الصفحة.

كل الحالات، بدون تمرير الفأرة

4 حالات

أو استورده من الحزمة

topclassui/slider
import { Slider } from 'topclassui/slider'

ثبّت مرة واحدة:npm i topclassui@beta zod

حقل رقمي

client - الحجم لم يُقَس بعد

رقم بين حدود معروفة، يُكتب أو يُزاد خطوة خطوة. حقل مخفي يحمل الرقم المجرد، فيُرسل النموذج قبل الترطيب.

تثبيت

جرّبه

size
invalid
fullWidth
min
max

الشيفرة

number-field.tsx
import { NumberField } from 'topclassui/number-field'

<div className="grid justify-items-start gap-2">
  <label htmlFor="number-field-playground-guests" className="text-sm text-body">Guests</label>
  <NumberField id="number-field-playground-guests" defaultValue={2} />
</div>

min وmax وstep تُحصر أثناء التشغيل، فلا تستطيع قيمة مكتوبة أو ممرَّرة أن تكسر الحقل.

كل الحالات، بدون تمرير الفأرة

4 حالات

أو استورده من الحزمة

topclassui/number-field
import { NumberField } from 'topclassui/number-field'

ثبّت مرة واحدة:npm i topclassui@beta zod

حقل رمز التحقق

client - الحجم لم يُقَس بعد

رمز يُستخدم مرة واحدة، حرف في كل خانة. اللصق يملأ كل الخانات، وحقل مخفي واحد يحمل الرمز إلى النموذج.

تثبيت

جرّبه

length
size
invalid
groupSize

الشيفرة

otp-field.tsx
import { OTPField } from 'topclassui/otp-field'

<div className="grid justify-items-start gap-2">
  <label htmlFor="otp-playground-code" className="text-sm text-body">Verification code</label>
  <OTPField id="otp-playground-code" />
</div>

اسم التصدير هو OTPField. داخل نموذج يرسل الحقل المخفي ما كُتب حتى الآن، حتى لو كان الرمز ناقصًا.

كل الحالات، بدون تمرير الفأرة

6 حالات

أو استورده من الحزمة

topclassui/otp-field
import { OtpField } from 'topclassui/otp-field'

ثبّت مرة واحدة:npm i topclassui@beta zod

منتقي التاريخ

client - الحجم لم يُقَس بعد, عند الطلب

يوم واحد يُختار من شهر. يُحمَّل التقويم عند فتحه أول مرة، وكل اسم شهر وكل رقم يأتي من Intl.

تثبيت

جرّبه

size
invalid
fullWidth
placement
firstDayOfWeek

الشيفرة

date-picker.tsx
import { DatePicker } from 'topclassui/date-picker'

<div className="grid justify-items-start gap-1.5">
  <label htmlFor="date-picker-playground" className="text-sm text-body">Check-in</label>
  <DatePicker id="date-picker-playground" defaultValue="2026-09-22" />
</div>

القيمة تاريخ بصيغة ISO، أي YYYY-MM-DD؛ والصيغة المعروضة تأتي من لغة المزوّد.

كل الحالات، بدون تمرير الفأرة

3 حالات
Pick a weekday.

أو استورده من الحزمة

topclassui/date-picker
import { DatePicker } from 'topclassui/date-picker'

ثبّت مرة واحدة:npm i topclassui@beta zod

رفع الملفات

client - الحجم لم يُقَس بعد

منطقة إفلات هي حقل ملفات حقيقي، فتعمل وتُرسل قبل تشغيل أي سكربت. والملفات المختارة تظهر في قائمة.

تثبيت

جرّبه

maxFiles
maxSize
invalid
visibleRows

الشيفرة

file-upload.tsx
import { FileUpload } from 'topclassui/file-upload'

<div className="grid gap-1.5">
  <label htmlFor="file-upload-playground" className="text-sm font-medium text-body">Attachment</label>
  <FileUpload id="file-upload-playground" name="attachment" accept=".png,.jpg,.jpeg,.pdf">
    PNG, JPG or PDF
  </FileUpload>
</div>

maxSize بالبايت، ويُتحقق منه في المتصفح فقط: تحقّق منه مجددًا في الإجراء.

كل الحالات، بدون تمرير الفأرة

حالتان
أفلت الملفات هناتصفّحA file is required
    أفلت الملفات هناتصفّحUploads are closed

      أو استورده من الحزمة

      topclassui/file-upload
      import { FileUpload } from 'topclassui/file-upload'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      التقييم

      split - الحجم لم يُقَس بعد

      نجوم القراءة فقط هي HTML من الخادم ولا تشحن أي سكربت. وحده التقييم القابل للتعديل يترطّب، كمجموعة أزرار راديو أصلية.

      تثبيت

      جرّبه

      value
      max
      size
      readOnly
      defaultValue
      disabled

      الشيفرة

      rating.tsx
      import { Rating } from 'topclassui/rating'
      import type { RatingDesignProps } from 'topclassui/rating'
      
      /** The site's Try it stage: each schema prop arrives from a control, and an absent one keeps its default. */
      export default function Demo(props: RatingDesignProps = {}) {
        const { readOnly, defaultValue, disabled, ...shown } = props
        if (readOnly === false) {
          return <Rating defaultValue={defaultValue ?? 3} disabled={disabled} {...shown} readOnly={false} aria-label="Rate this course" />
        }
        return <Rating value={3.5} {...shown} />
      }
      

      value وحده يعرض النجوم على الخادم؛ ووحده readOnly={false} يشحن نصف العميل.

      كل الحالات، بدون تمرير الفأرة

      6 حالات

      أو استورده من الحزمة

      topclassui/rating
      import { Rating } from 'topclassui/rating'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      العرض

      7 مكوّنات

      قطع للعرض. كلها تقريبًا تُعرض على الخادم ولا ترسل أي JavaScript، وحين يضيف أحدها زرًا، مثل Tag القابل للإزالة، تقول ذلك الشارة على بطاقته.

      شارة

      server - 0 KB

      تسمية حالة قصيرة بثلاثة أنماط عبر ست نبرات. تُعرض على الخادم ولا تُرسل أي JavaScript إلى المتصفح.

      تثبيت
      Paid

      جرّبه

      variant
      tone
      size

      الشيفرة

      badge.tsx
      import { Badge } from 'topclassui/badge'
      
      <Badge>Paid</Badge>

      لا تحمل الشارة أي دور ARIA: النص يحمل المعنى، واللون وحده لا يكفي أبدًا.

      كل الحالات، بدون تمرير الفأرة

      3 حالات
      SolidSoftOutline

      أو استورده من الحزمة

      topclassui/badge
      import { Badge } from 'topclassui/badge'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      صورة رمزية

      split - الحجم لم يُقَس بعد

      صورة أو أحرف أولى أو أيقونة داخل دائرة، بالأحجام الخمسة نفسها لكل عنصر تحكم، فتصطف الصورة الرمزية مع الزر في الصف نفسه.

      تثبيت
      Omar Abed

      جرّبه

      size

      الشيفرة

      avatar.tsx
      import { AvatarFallback, AvatarImage, AvatarRoot } from 'topclassui/avatar'
      
      <AvatarRoot>
        <AvatarImage src={PORTRAIT} alt="Omar Abed" />
        <AvatarFallback>OA</AvatarFallback>
      </AvatarRoot>

      يظهر البديل أثناء تحميل الصورة وبعد فشلها؛ والأحرف الأولى هي محتواه.

      كل الحالات، بدون تمرير الفأرة

      5 حالات
      Omar AbedImage
      Initials
      Icon
      Sara KhalilFailed
      Loading

      أو استورده من الحزمة

      topclassui/avatar
      import { AvatarRoot, AvatarImage, AvatarFallback, AvatarSkeleton } from 'topclassui/avatar'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      صور رمزية متداخلة مع عدّاد +N للبقية. اعرض كل الأعضاء؛ وتُحصر قيمة max بين 1 و20.

      تثبيت

      جرّبه

      max
      size

      الشيفرة

      avatar-group.tsx
      import { AvatarFallback, AvatarRoot } from 'topclassui/avatar'
      import { AvatarGroup } from 'topclassui/avatar-group'
      
      <AvatarGroup aria-label="Project team">
        {TEAM.map(([initials, name]) => (
          <AvatarRoot key={initials} size={props.size} role="img" aria-label={name}>
            <AvatarFallback>{initials}</AvatarFallback>
          </AvatarRoot>
        ))}
      </AvatarGroup>

      تعدّ max العناصر الأبناء، فاعرض كل عضو ودع المجموعة تخفي الفائض.

      كل الحالات، بدون تمرير الفأرة

      حالة واحدة
      Two
      Four
      Overflow

      أو استورده من الحزمة

      topclassui/avatar-group
      import { AvatarGroup } from 'topclassui/avatar-group'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      بطاقة

      server - 0 KB

      سطح لمحتوى يجمعه موضوع واحد، باستدارة أكبر من استدارة عنصر التحكم كي لا تبدو البطاقة زرًا أبدًا.

      تثبيت

      Storage

      You have used 18 GB of the 50 GB in your plan.

      الشيفرة

      card.tsx
      import { CardBody, CardHeader, CardRoot } from 'topclassui/card'
      
      /** The first drawing: a title and a line of text, with nothing to press. */
      export default function Demo() {
        return (
          <div className="max-w-xs">
            <CardRoot>
              <CardHeader>
                <h2>Storage</h2>
              </CardHeader>
              <CardBody>You have used 18 GB of the 50 GB in your plan.</CardBody>
            </CardRoot>
          </div>
        )
      }
      

      تحدد البطاقة خط عنوانها وتترك لك مستوى العنوان: ضع h2 أو h3 داخل CardHeader.

      كل الحالات، بدون تمرير الفأرة

      3 حالات

      Storage

      You have used 18 GB of the 50 GB in your plan.
      Idle

      Version 0.4

      Card is now CardRoot. Find and replace; nothing else changed.
      With actions
      Loading

      أو استورده من الحزمة

      topclassui/card
      import { CardRoot, CardHeader, CardBody, CardFooter, CardSkeleton } from 'topclassui/card'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      فاصل

      server - 0 KB

      خط رفيع بين مجموعتين، عرضيًا في عمود أو طوليًا في صف. زخرفي افتراضيًا، فلا يُعلَن لقارئ الشاشة.

      تثبيت
      Profile
      Billing

      جرّبه

      orientation
      decorative

      الشيفرة

      separator.tsx
      import { Separator } from 'topclassui/separator'
      
      <div className="flex min-h-5 flex-wrap items-center gap-3 text-sm text-body">
        <span>Profile</span>
        <Separator />
        <span>Billing</span>
      </div>

      يأخذ الفاصل العمودي ارتفاعه من صف flex أو grid؛ أعطِ الصف ارتفاعًا أو دعه يتمدد.

      كل الحالات، بدون تمرير الفأرة

      حالتان
      Account
      Security
      Horizontal
      Draft
      Edited 2 hours ago
      Vertical

      أو استورده من الحزمة

      topclassui/separator
      import { Separator } from 'topclassui/separator'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      عنصر نائب يحجز شكل المحتوى أثناء تحميله: أسطر نص، أو دائرة، أو مستطيل، أو بطاقة.

      تثبيت

      جرّبه

      variant
      rows

      الشيفرة

      skeleton.tsx
      import { Skeleton } from 'topclassui/skeleton'
      
      <div className="max-w-sm">
        <Skeleton />
      </div>

      أعطِ الهيكل الأبعاد الحقيقية عبر className؛ تُحصر rows بين 1 و50، والحجم الخاطئ يعني إزاحة في التخطيط.

      كل الحالات، بدون تمرير الفأرة

      حالة واحدة
      Text
      Circle
      Rect
      Card

      أو استورده من الحزمة

      topclassui/skeleton
      import { Skeleton } from 'topclassui/skeleton'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      كتلة شيفرة

      split - الحجم لم يُقَس بعد

      شيفرة في صندوق خاص بها، تُقرأ من اليسار إلى اليمين في أي صفحة. تُعرض على الخادم، وزر النسخ هو الشيفرة الوحيدة في المتصفح.

      تثبيت
      app/invoices/page.tsx
      export default async function Page() {
        const invoices = await getInvoices({ status: 'overdue', sortBy: 'dueDate', order: 'descending' })
        return <InvoiceTable items={invoices} />
      }

      جرّبه

      showCopy
      wrap

      الشيفرة

      code-block.tsx
      import type { CodeBlockDesignProps } from 'topclassui/code-block'
      import { CodeBlock } from 'topclassui/code-block'
      
      /** The docs stage: the Try it controls hand their values in as props. One line is long, so wrap shows. */
      export default function Demo(props: CodeBlockDesignProps) {
        return (
          <CodeBlock lang="tsx" title="app/invoices/page.tsx" {...props}>
            {`export default async function Page() {
        const invoices = await getInvoices({ status: 'overdue', sortBy: 'dueDate', order: 'descending' })
        return <InvoiceTable items={invoices} />
      }`}
          </CodeBlock>
        )
      }
      

      مرّر الشيفرة ابنًا بصيغة template literal. لا يوجد ملوّن مدمج: مرّر العقد الملوّنة عبر highlighted.

      كل الحالات، بدون تمرير الفأرة

      3 حالات
      app/page.tsx
      export default async function Page() {
        const invoices = await getInvoices()
        return <InvoiceTable items={invoices} />
      }
      Idle
      columns.ts
      export const columns = ['number', 'customer', 'issued', 'due', 'amount', 'status', 'actions'] as const
      Wrapped
      app/reports/page.tsx
      export default async function Page() {
        const invoices = await getInvoices()
        return <InvoiceTable items={invoices} />
      }
      No copy button

      أو استورده من الحزمة

      topclassui/code-block
      import { CodeBlock } from 'topclassui/code-block'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      البيانات

      4 مكوّنات

      كل مكوّن قائمة يعمل بالطريقة نفسها: خاصية للصفوف الظاهرة، وعرض نافذي فوق 200 عنصر، ودالة loadMore. ولا يجلب البيانات بنفسه أبدًا.

      جدول

      split - الحجم لم يُقَس بعد

      جدول HTML حقيقي يُعرض على الخادم: الترتيب رابط في كل عنوان عمود، والعمود الأول يمكن تثبيته، ولا يشحن أي JavaScript.

      تثبيت
      Quarterly revenue by region
      RegionQ1Q2Q3Q4Full year
      Middle East$412,000$455,300$498,120$530,900$1,896,320
      North Africa$208,400$214,950$240,010$262,700$926,060
      Western Europe$890,150$874,600$910,480$955,230$3,630,460
      North America$1,204,800$1,260,340$1,315,900$1,402,650$5,183,690

      جرّبه

      captionVisible
      striped
      stickyFirstColumn
      visibleRows
      loadMoreThreshold

      الشيفرة

      table.tsx
      import { Table, type TableDesignProps } from 'topclassui/table'
      
      <Table
      
        caption="Quarterly revenue by region"
        items={regions}
        getKey={(region) => region.name}
        columns={[
          { key: 'name', header: 'Region', rowHeader: true, cell: (region) => region.name },
          { key: 'q1', header: 'Q1', align: 'end', cell: (region) => region.q1 },
          { key: 'q2', header: 'Q2', align: 'end', cell: (region) => region.q2 },
          { key: 'q3', header: 'Q3', align: 'end', cell: (region) => region.q3 },
          { key: 'q4', header: 'Q4', align: 'end', cell: (region) => region.q4 },
          { key: 'total', header: 'Full year', align: 'end', cell: (region) => region.total },
        ]}
      />

      الترتيب رابط يجيب عنه الخادم بالصفوف في ترتيبها الجديد، فلا يكلّف الجدول المرتّب أي JavaScript.

      كل الحالات، بدون تمرير الفأرة

      7 حالات
      Deploys
      DeploySort by BranchAuthorSort by Duration
      dpl_7f3amainLayla Haddad48 s
      dpl_7f39fix/checkout-totalOmar Abed51 s
      dpl_7f38mainSara Nasser47 s
      Deploys, caption drawn
      DeploySort by BranchAuthorSort by Duration
      dpl_7f3amainLayla Haddad48 s
      dpl_7f39fix/checkout-totalOmar Abed51 s
      dpl_7f38mainSara Nasser47 s
      Deploys, striped
      DeploySort by BranchAuthorSort by Duration
      dpl_7f3amainLayla Haddad48 s
      dpl_7f39fix/checkout-totalOmar Abed51 s
      dpl_7f38mainSara Nasser47 s
      Deploys, slowest first
      DeploySort by BranchAuthorSort by Duration
      dpl_7f3amainLayla Haddad48 s
      dpl_7f39fix/checkout-totalOmar Abed51 s
      dpl_7f38mainSara Nasser47 s
      Deploys, first column stuck
      DeploySort by BranchAuthorSort by Duration
      dpl_7f3amainLayla Haddad48 s
      dpl_7f39fix/checkout-totalOmar Abed51 s
      dpl_7f38mainSara Nasser47 s
      Deploys, none yet
      DeploySort by BranchAuthorSort by Duration
      Nothing here yet

      أو استورده من الحزمة

      topclassui/table
      import { Table } from 'topclassui/table'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      عرض شجري

      client - الحجم لم يُقَس بعد

      عقد في مستويات تُفتح وتُغلق. الفروع المفتوحة تُسطَّح في قائمة واحدة تعرض ما يظهر فقط، فتبقى 10,000 عقدة سريعة.

      تثبيت

      جرّبه

      visibleRows
      loadMoreThreshold
      status

      الشيفرة

      tree-view.tsx
      import { fileText } from 'topclassui/icons/file-text'
      import { folder } from 'topclassui/icons/folder'
      import { Svg } from 'topclassui/svg'
      import { TreeView, type TreeViewDesignProps } from 'topclassui/tree-view'
      
      <TreeView aria-label="Files" items={ITEMS} defaultExpanded={['src', 'app']} />

      items بيانات عادية وأيقونة العقدة عنصر، فيمرّر مكوّن الخادم الشجرة كما هي، ولا يوجد getKey.

      كل الحالات، بدون تمرير الفأرة

      4 حالات
      app
      layout.tsx
      page.tsx
      docs
      guide.md
      faq.md
      next.config.ts
      next.config.ts
      جارٍ تحميل المزيد
      جارٍ التحميل
      لا يوجد شيء بعد

      أو استورده من الحزمة

      topclassui/tree-view
      import { TreeView } from 'topclassui/tree-view'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      خط زمني

      server - 0 KB

      مسار من الأحداث المؤرّخة، لكل حدث علامة بنبرته. يُعرض على الخادم وينعكس وحده في التخطيطات من اليمين إلى اليسار.

      تثبيت
      1. Done
        Project created
      2. Done
        First deploy
      3. Current
        In review
        Today
      4. Not started
        Launch
        Not scheduled

      الشيفرة

      timeline.tsx
      import { Timeline } from 'topclassui/timeline'
      
      const EVENTS = [
        { id: 'created', title: 'Project created', time: <time dateTime="2026-10-02T09:12">2 October, 09:12</time>, status: 'done' },
        { id: 'deployed', title: 'First deploy', time: <time dateTime="2026-10-04T16:40">4 October, 16:40</time>, status: 'done' },
        { id: 'review', title: 'In review', time: 'Today', status: 'current' },
        { id: 'launch', title: 'Launch', time: 'Not scheduled', status: 'todo' },
      ] as const
      
      /** The drawn rail: done filled in success, the current step a dot in a ring, and a hollow todo.
       * A `<time>` gives a date a machine can read; each status is also said in hidden text. */
      export default function Demo() {
        return <Timeline items={EVENTS} getKey={(event) => event.id} />
      }
      

      أيقونة العنصر عنصرٌ، مثل <Svg icon={check} size="xs" />، لا اسم أيقونة: لا يُشحن أي محمّل أيقونات.

      كل الحالات، بدون تمرير الفأرة

      6 حالات
      1. Done
        Done
        A filled dot in success
      1. Current
        Current
        A dot in a ring, read as the current step
      1. Not started
        To do
        A hollow dot
      1. A tone of its own
        No status, the danger tone
      1. Done
        An icon
        Takes the tone of its status
      1. Not started
        An icon to do

      أو استورده من الحزمة

      topclassui/timeline
      import { Timeline } from 'topclassui/timeline'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      أين يقف القارئ في مهمة من بضع خطوات. الخطوة المكتملة تحمل علامة صح لا لونًا فقط، فتبقى واضحة في لقطة شاشة رمادية.

      تثبيت
      1. AccountCompleted
      2. Profile
      3. TeamNot started
      4. DoneNot started

      جرّبه

      size

      الشيفرة

      stepper.tsx
      import { Stepper, type StepperDesignProps } from 'topclassui/stepper'
      
      <Stepper items={STEPS} value="profile" aria-label="Sign-up" />

      مؤشر الخطوات يُعرض على الخادم: مرّر value، أي معرّف الخطوة الحالية. هو يعرض التقدّم ولا ينقل بين الصفحات.

      كل الحالات، بدون تمرير الفأرة

      4 حالات
      1. Cart
      2. AddressNot started
      3. PaymentNot started
      1. CartCompleted
      2. Address
      3. PaymentNot started
      1. CartCompleted
      2. AddressNeeds attention
      3. PaymentNot started
      1. CartCompleted
      2. AddressCompleted
      3. PaymentCompleted

      أو استورده من الحزمة

      topclassui/stepper
      import { Stepper } from 'topclassui/stepper'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      التنبيهات

      6 مكوّنات

      الحالة والتقدم والحالات الفارغة. يعلن Toast وProgress عن نفسيهما لقارئ الشاشة، والبقية تبقى صامتة.

      تنبيه

      server - 0 KB

      رسالة تنتمي إلى الصفحة، بست نبرات. لكلٍّ من المعلومة والنجاح والتحذير والخطر أيقونتها الخاصة، فتُقرأ الرسالة دون الاعتماد على اللون.

      تثبيت

      Your trial ends in three days

      Deploys pause when it does. Adding a payment method turns them back on.

      جرّبه

      variant
      tone

      الشيفرة

      alert.tsx
      import { Alert } from 'topclassui/alert'
      
      <Alert title="Your trial ends in three days">
        Deploys pause when it does. Adding a payment method turns them back on.
      </Alert>

      ليس منطقة حية: إنه جزء من محتوى الصفحة. مرّر role="alert" إذا ظهر بعد التحميل، أو أعلن الحدث بإشعار.

      كل الحالات، بدون تمرير الفأرة

      13 حالة

      Soft

      A tint of the tone.

      Solid

      The full fill.

      Outline

      A line in the tone colour.

      Primary

      A new version is ready.

      Neutral

      Nothing has changed since Monday.

      Success

      The invoice was paid.

      Warning

      The trial ends in three days.

      Danger

      The last deploy failed.

      Info

      Maintenance starts at 22:00.

      Title only

      Description only, with no title above it.

      No icon

      The icon is left out.

      With actions

      Actions sit in a row under the description.

      أو استورده من الحزمة

      topclassui/alert
      import { Alert } from 'topclassui/alert'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      إشعار

      client - الحجم لم يُقَس بعد

      إشعار قصير بأن شيئًا حدث. يظهر في زاوية ويغادر وحده، وفيه دائمًا زر إغلاق، لأن السحب بالإصبع حركة جرّ.

      تثبيت

      جرّبه

      tone
      duration
      priority

      الشيفرة

      toast.tsx
      'use client'
      
      import { Button } from 'topclassui/button'
      import { toast } from 'topclassui/toast'
      import type { ToastDesignProps } from 'topclassui/toast'
      
      /** The docs stage: the Try it controls set the options of the toast the press adds. */
      export default function Demo(props: ToastDesignProps = {}) {
        return (
          <Button
            variant="outline"
            onClick={() => { toast.add({ ...props, title: 'Project created', description: 'It is ready for its first deploy.' }) }}
          >
            Show a toast
          </Button>
        )
      }
      

      TopClassProvider يركّب منطقة العرض الوحيدة، فلا شيء عليك تركيبه؛ وtoast.add يعمل من أي وحدة في المتصفح، داخل React أو خارجه.

      كل الحالات، بدون تمرير الفأرة

      11 حالة

      أو استورده من الحزمة

      topclassui/toast
      import { Toast } from 'topclassui/toast'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      شريط إعلان

      split - الحجم لم يُقَس بعد

      رسالة واحدة للصفحة كلها، بعرض كامل فوق الترويسة. يقع في تدفق الصفحة، فيدفعها إلى الأسفل ولا يغطي شيئًا.

      تثبيت

      جرّبه

      tone
      dismissible

      الشيفرة

      banner.tsx
      import { bell } from 'topclassui/icons/bell'
      import { Button } from 'topclassui/button'
      import { Svg } from 'topclassui/svg'
      import { Banner } from 'topclassui/banner'
      
      <Banner
        id="banner-playground"
        aria-label="Version 2 announcement"
        icon={<Svg icon={bell} size="xs" />}
        action={<Button size="sm" variant="outline" tone="neutral" render={<a href="/changelog" />}>Read the changelog</Button>}
      >
        Version 2 is out, with faster builds and a new theme editor.
      </Banner>

      الإخفاء يُحفظ حسب المعرّف في هذا المتصفح، فغيّر المعرّف عندما تتغير الرسالة.

      كل الحالات، بدون تمرير الفأرة

      9 حالات
      Primary
      Neutral
      Success
      Warning
      Danger
      Info
      No icon
      With action

      أو استورده من الحزمة

      topclassui/banner
      import { Banner } from 'topclassui/banner'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      إلى أين وصلت المهمة: مسار محايد عليه شريط بلون النبرة، يقرؤه قارئ الشاشة شريطَ تقدم من 0 إلى 100.

      تثبيت

      جرّبه

      value
      tone
      size
      indeterminate

      الشيفرة

      progress.tsx
      import { Progress } from 'topclassui/progress'
      
      <div className="grid max-w-sm">
        <Progress aria-label="Upload" />
      </div>

      لا يعرض أي نص ويحصر القيمة بين 0 و100، فسمِّه بـ aria-label أو aria-labelledby.

      كل الحالات، بدون تمرير الفأرة

      5 حالات
      Empty
      Part way
      Complete
      Indeterminate
      Tones

      أو استورده من الحزمة

      topclassui/progress
      import { Progress } from 'topclassui/progress'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      للانتظار مجهول المدة. مؤشر التحميل أيقونة، فيأخذ أحجام الأيقونات من 16 إلى 40 بكسل، ويمكنه أن يتبع النص الذي يجلس فيه.

      تثبيت

      جرّبه

      size
      tone

      الشيفرة

      spinner.tsx
      import { Spinner } from 'topclassui/spinner'
      
      <Spinner />

      فضّل Skeleton عندما يكون شكل القادم معروفًا؛ مؤشر التحميل للانتظار المجهول.

      كل الحالات، بدون تمرير الفأرة

      3 حالات

      Decorative, in the text colour

      أو استورده من الحزمة

      topclassui/spinner
      import { Spinner } from 'topclassui/spinner'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      ما تعرضه القائمة أو الجدول أو البحث حين لا يوجد ما يُعرض: أيقونة وسطر وجملة وإجراء من عندك.

      تثبيت

      Nothing here yet

      When there is something to show, it will appear here.

      الشيفرة

      empty-state.tsx
      import { EmptyState } from 'topclassui/empty-state'
      
      /** No props at all: the tray icon, then the English title and description from labels. */
      export default function Demo() {
        return (
          <div className="max-w-85">
            <EmptyState />
          </div>
        )
      }
      

      بلا خصائص يعرض أيقونة الدُّرج ونصّي labels.state؛ وعنوانك الخاص يُسقط الوصف الافتراضي.

      كل الحالات، بدون تمرير الفأرة

      5 حالات

      Nothing here yet

      When there is something to show, it will appear here.

      Title only

      With action

      The action is the caller's own Button.

      Failed

      Check your connection, then try again.

      Filtered

      Nothing matches that search.

      أو استورده من الحزمة

      topclassui/empty-state
      import { EmptyState } from 'topclassui/empty-state'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      الطبقات

      6 مكوّنات

      تشترك الطبقات في قاعدة تمرير واحدة: تتمرر الطبقة ولا تتمرر الصفحة خلفها. والموضع منطقي، فينعكس في العربية.

      مربع حوار

      client - الحجم لم يُقَس بعد

      مربع حوار يحجب الصفحة، يتمرّر متنه بين رأس وتذييل ثابتين، بينما تبقى الصفحة خلفه ساكنة.

      تثبيت

      جرّبه

      size
      closeButton

      الشيفرة

      dialog.tsx
      import { Button } from 'topclassui/button'
      import {
      
      <DialogRoot>
        <DialogTrigger render={<Button>Publish</Button>} />
        <DialogPopup>
          <DialogHeader>
            <DialogTitle>Publish changes</DialogTitle>
            <DialogDescription>Your changes go live right away.</DialogDescription>
          </DialogHeader>
          <DialogBody>11 files changed since the last publish.</DialogBody>
          <DialogFooter>
            <DialogClose render={<Button variant="outline">Cancel</Button>} />
            <DialogClose render={<Button>Publish now</Button>} />
          </DialogFooter>
        </DialogPopup>
      </DialogRoot>

      غلّف الأجزاء بنموذج يحمل الصنف contents، فيُرسَل إجراء الخادم من التذييل دون أي معالج في المتصفح.

      كل الحالات، بدون تمرير الفأرة

      5 حالات

      أو استورده من الحزمة

      topclassui/dialog
      import { DialogRoot, DialogBody, DialogClose, DialogDescription, DialogFooter, DialogHeader, DialogPopup, DialogTitle, DialogTrigger } from 'topclassui/dialog'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      درج

      client - الحجم لم يُقَس بعد

      مربع حوار ينزلق من حافة منطقية، فينعكس في العربية دون أي تعديل في الشيفرة. يُغلق بالسحب أو بزر الإغلاق.

      تثبيت

      جرّبه

      placement
      size

      الشيفرة

      drawer.tsx
      import { Button } from 'topclassui/button'
      import {
      
      <DrawerRoot>
        <DrawerTrigger render={<Button variant="outline">Filters</Button>} />
        <DrawerPopup>
          <DrawerHeader>
            <DrawerTitle>Filters</DrawerTitle>
            <DrawerDescription>Narrow the list of projects.</DrawerDescription>
          </DrawerHeader>
          <DrawerBody className="grid content-start gap-2.5">
            <p>Status</p>
            <p>Owner</p>
            <p>Updated</p>
          </DrawerBody>
          <DrawerFooter>
            <DrawerClose render={<Button variant="outline">Reset</Button>} />
            <DrawerClose render={<Button>Apply</Button>} />
          </DrawerFooter>
        </DrawerPopup>
      </DrawerRoot>

      placement منطقي: start يفتح من اليسار في الإنجليزية ومن اليمين في العربية. لا left ولا right أبدًا.

      كل الحالات، بدون تمرير الفأرة

      5 حالات

      أو استورده من الحزمة

      topclassui/drawer
      import { DrawerRoot, DrawerBody, DrawerClose, DrawerDescription, DrawerFooter, DrawerHeader, DrawerPopup, DrawerTitle, DrawerTrigger } from 'topclassui/drawer'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      نافذة منبثقة

      client - الحجم لم يُقَس بعد

      لوحة مثبّتة بجانب مشغّلها لرابط أو حقل أو إجراء. تنقلب وتتقلّص إلى المساحة المتاحة بدلًا من أن تفيض.

      تثبيت

      جرّبه

      placement
      delay
      closeDelay

      الشيفرة

      popover.tsx
      import { Button } from 'topclassui/button'
      import { PopoverDescription, PopoverPopup, PopoverRoot, PopoverTitle, PopoverTrigger } from 'topclassui/popover'
      
      <PopoverRoot>
        <PopoverTrigger openOnHover render={<Button variant="outline">Share</Button>} />
        <PopoverPopup>
          <PopoverTitle>Share this page</PopoverTitle>
          <PopoverDescription>Anyone with the link can read it. Only your team can edit.</PopoverDescription>
          <Button size="sm" className="self-start">Copy link</Button>
        </PopoverPopup>
      </PopoverRoot>

      التلميح نص فقط: أبناؤه مكتوبون كنص. كل ما فيه رابط أو عنصر تحكم هو نافذة منبثقة.

      كل الحالات، بدون تمرير الفأرة

      5 حالات

      أو استورده من الحزمة

      topclassui/popover
      import { PopoverRoot, PopoverClose, PopoverDescription, PopoverPopup, PopoverTitle, PopoverTrigger } from 'topclassui/popover'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      تلميح

      client - الحجم لم يُقَس بعد

      سطر أو سطران من النص عند التمرير أو التركيز: اسم عنصر تحكم بأيقونة فقط، أو تسمية مقطوعة.

      تثبيت

      جرّبه

      placement
      delay
      closeDelay

      الشيفرة

      tooltip.tsx
      import { linkSimple } from 'topclassui/icons/link-simple'
      import { Button } from 'topclassui/button'
      import { Svg } from 'topclassui/svg'
      import { TooltipPopup, TooltipRoot, TooltipTrigger } from 'topclassui/tooltip'
      
      <TooltipRoot>
        <TooltipTrigger
          render={
            <Button variant="ghost" aria-label="Copy link">
              <Svg icon={linkSimple} />
            </Button>
          }
        />
        <TooltipPopup>Copy link</TooltipPopup>
      </TooltipRoot>

      شاشات اللمس لا تعرض التلميح أبدًا، فيجب أن يكرّر اسم المشغّل النص نفسه: أعطِ الزر ذا الأيقونة فقط aria-label.

      كل الحالات، بدون تمرير الفأرة

      4 حالات

      أو استورده من الحزمة

      topclassui/tooltip
      import { TooltipRoot, TooltipPopup, TooltipTrigger } from 'topclassui/tooltip'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      قائمة منسدلة

      client - الحجم لم يُقَس بعد

      قائمة إجراءات وروابط خلف زر واحد. صفوف الروابط روابط حقيقية، فيعمل الفتح في علامة تبويب جديدة والنقر بالزر الأوسط.

      تثبيت

      جرّبه

      placement
      tone
      delay
      closeDelay

      الشيفرة

      dropdown.tsx
      import { copy } from 'topclassui/icons/copy'
      import { gear } from 'topclassui/icons/gear'
      import { trash } from 'topclassui/icons/trash'
      import { user } from 'topclassui/icons/user'
      import { Button } from 'topclassui/button'
      import { Svg } from 'topclassui/svg'
      import { DropdownItem, DropdownPopup, DropdownRoot, DropdownSeparator, DropdownTrigger } from 'topclassui/dropdown'
      
      <DropdownRoot>
        <DropdownTrigger openOnHover render={<Button variant="outline">Actions</Button>} />
        <DropdownPopup>
          <DropdownItem icon={<Svg icon={user} />} shortcut="Ctrl P">Profile</DropdownItem>
          <DropdownItem icon={<Svg icon={gear} />}>Settings</DropdownItem>
          <DropdownItem icon={<Svg icon={copy} />}>Duplicate</DropdownItem>
          <DropdownSeparator />
          <DropdownItem icon={<Svg icon={trash} />}>Delete</DropdownItem>
        </DropdownPopup>
      </DropdownRoot>

      عناصر href وإجراء الخادم تعمل من صفحة خادم؛ أما onSelect فدالة عادية تحتاج ملف عميل.

      كل الحالات، بدون تمرير الفأرة

      4 حالات

      أو استورده من الحزمة

      topclassui/dropdown
      import { DropdownRoot, DropdownGroup, DropdownGroupLabel, DropdownItem, DropdownLinkItem, DropdownMenu, DropdownPopup, DropdownSeparator, DropdownTrigger } from 'topclassui/dropdown'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      لوحة الأوامر

      client - الحجم لم يُقَس بعد, عند الطلب

      لوحة أوامر قابلة للبحث تُفتح بـ Ctrl+K أو Cmd+K. تُحمَّل عند أول فتح لها، لا مع الصفحة أبدًا.

      تثبيت

      جرّبه

      visibleRows
      loadMoreThreshold
      defaultOpen

      الشيفرة

      command.tsx
      'use client'
      
      import { useState } from 'react'
      
      import { magnifyingGlass } from 'topclassui/icons/magnifying-glass'
      import { Button } from 'topclassui/button'
      import { Svg } from 'topclassui/svg'
      import { Command } from 'topclassui/command'
      import type { CommandDesignProps } from 'topclassui/command'
      
      interface Entry { id: string, label: string }
      
      const COMMANDS: Entry[] = [
        { id: 'button', label: 'Button' },
        { id: 'dialog', label: 'Dialog' },
        { id: 'drawer', label: 'Drawer' },
        { id: 'popover', label: 'Popover' },
        { id: 'tabs', label: 'Tabs' },
        { id: 'accordion', label: 'Accordion' },
        { id: 'table', label: 'Table' },
        { id: 'pagination', label: 'Pagination' },
        { id: 'breadcrumb', label: 'Breadcrumb' },
        { id: 'tooltip', label: 'Tooltip' },
      ]
      
      /** The docs stage: the basic palette, with the schema's props passed through, so the Try it
       * controls drive it. defaultOpen is where the open state starts; the Button opens it too. */
      export default function Demo({ visibleRows, virtualize, shortcut, defaultOpen }: CommandDesignProps = {}) {
        const [open, setOpen] = useState(defaultOpen ?? false)
        return (
          <div className="grid justify-items-start gap-3">
            <Button variant="outline" onClick={() => { setOpen(true) }}><Svg icon={magnifyingGlass} />Search</Button>
            <Command
              items={COMMANDS}
              getKey={(command) => command.id}
              getLabel={(command) => command.label}
              onSelect={() => undefined}
              visibleRows={visibleRows}
              virtualize={virtualize}
              shortcut={shortcut}
              open={open}
              onOpenChange={setOpen}
            />
          </div>
        )
      }
      

      getKey وgetLabel وonSelect دوال، لذا تُضبط اللوحة داخل ملف عميل.

      كل الحالات، بدون تمرير الفأرة

      6 حالات

      أو استورده من الحزمة

      topclassui/command
      import { Command } from 'topclassui/command'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      6 مكوّنات

      الروابط روابط. كل واحد من هذه يعرض <a href> حقيقيًا، فيعمل النقر بالزر الأوسط والفتح في علامة تبويب جديدة وزواحف البحث.

      شريط التنقّل

      split - الحجم لم يُقَس بعد

      ترويسة مثبّتة روابطها HTML من الخادم، ويكتب جزء صغير واحد في المتصفح ارتفاعها في --tc-sticky-top.

      تثبيت

      الشيفرة

      navbar.tsx
      import { Button } from 'topclassui/button'
      import { NavbarActions, NavbarBrand, NavbarLink, NavbarLinks, NavbarRoot } from 'topclassui/navbar'
      
      <NavbarRoot>
        <NavbarBrand href="/">TopClass UI</NavbarBrand>
        <NavbarLinks>
          <NavbarLink href="/docs">Docs</NavbarLink>
          <NavbarLink href="/components">Components</NavbarLink>
          <NavbarLink href="/icons">Icons</NavbarLink>
        </NavbarLinks>
        <NavbarActions>
          <Button render={<a href="/login" />}>Sign in</Button>
        </NavbarActions>
      </NavbarRoot>

      يكتب الشريط ارتفاعه في --tc-sticky-top، فيتوقف هدف الرابط #anchor تحته لا خلفه.

      كل الحالات، بدون تمرير الفأرة

      حالتان

      أو استورده من الحزمة

      topclassui/navbar
      import { NavbarRoot, NavbarBrand, NavbarLinks, NavbarLink, NavbarActions } from 'topclassui/navbar'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      الشريط الجانبي

      split - الحجم لم يُقَس بعد

      شريط جانبي روابطه تُعرض على الخادم، وينطوي إلى عمود من الأيقونات. الشريط وزرّه وحدهما يعملان في المتصفح.

      تثبيت

      جرّبه

      defaultOpen
      open
      current

      الشيفرة

      sidebar.tsx
      import { folder } from 'topclassui/icons/folder'
      import { gear } from 'topclassui/icons/gear'
      import { house } from 'topclassui/icons/house'
      import { Svg } from 'topclassui/svg'
      import { SidebarBody, SidebarGroup, SidebarHeader, SidebarLink, SidebarRoot } from 'topclassui/sidebar'
      
      <div className="h-96">
        <SidebarRoot>
          <SidebarHeader>Workspace</SidebarHeader>
          <SidebarBody>
            <SidebarGroup>
              <SidebarLink href="#home" icon={<Svg icon={house} />}>Home</SidebarLink>
              <SidebarLink href="#projects" icon={<Svg icon={folder} />}>Projects</SidebarLink>
              <SidebarLink href="#settings" icon={<Svg icon={gear} />}>Settings</SidebarLink>
            </SidebarGroup>
          </SidebarBody>
        </SidebarRoot>
      </div>

      مع defaultOpen={false} يرسل الخادم الشريط مطويًّا، فلا يتحرك شيء عند الترطيب.

      كل الحالات، بدون تمرير الفأرة

      حالتان

      أو استورده من الحزمة

      topclassui/sidebar
      import { SidebarRoot, SidebarTrigger, SidebarHeader, SidebarBody, SidebarGroup, SidebarLink } from 'topclassui/sidebar'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      علامات التبويب

      split - الحجم لم يُقَس بعد

      عروض متعددة لشيء واحد، يظهر منها واحد في كل مرة. كل لوحة تُعرض على الخادم وتبقى في HTML، فيُفهرَس النص المخفي أيضًا.

      تثبيت
      Revenue is up 12% against last quarter.

      جرّبه

      variant
      size
      keepMounted

      الشيفرة

      tabs.tsx
      import { TabsList, TabsPanel, TabsRoot, TabsTab } from 'topclassui/tabs'
      
      <TabsRoot defaultValue="overview">
        <TabsList aria-label="Project">
          <TabsTab value="overview">Overview</TabsTab>
          <TabsTab value="activity">Activity</TabsTab>
          <TabsTab value="settings">Settings</TabsTab>
        </TabsList>
        <TabsPanel value="overview">Revenue is up 12% against last quarter.</TabsPanel>
        <TabsPanel value="activity">Three people edited this project today.</TabsPanel>
        <TabsPanel value="settings">Only an owner can rename or delete this project.</TabsPanel>
      </TabsRoot>

      keepMounted هنا true، وقيمته في Base UI هي false: اللوحات غير النشطة تبقى مخفية في HTML القادم من الخادم.

      كل الحالات، بدون تمرير الفأرة

      حالتان
      The active tab is semibold over a bar of the primary colour.
      The active tab sits on a raised surface.

      أو استورده من الحزمة

      topclassui/tabs
      import { TabsRoot, TabsList, TabsPanel, TabsTab } from 'topclassui/tabs'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      الأكورديون

      split - الحجم لم يُقَس بعد

      أقسام يفتحها القارئ واحدًا تلو الآخر. اللوحات المغلقة تبقى في HTML، فيقرؤها الزاحف ويفتحها البحث في الصفحة.

      تثبيت

      جرّبه

      hiddenUntilFound
      headingLevel

      الشيفرة

      accordion.tsx
      import { AccordionItem, AccordionRoot } from 'topclassui/accordion'
      
      <AccordionRoot className="max-w-105">
        <AccordionItem value="server" title="What is a server component?">
          <p>A component that renders on the server and sends HTML, with no JavaScript of its own.</p>
        </AccordionItem>
        <AccordionItem value="arabic" title="Does it work in Arabic?">
          <p>Yes. The caret moves to the left edge and the text starts at the right one.</p>
        </AccordionItem>
        <AccordionItem value="bundle" title="How big is the bundle?">
          <p>About one kilobyte in the browser. The answers cost nothing: they are plain HTML.</p>
        </AccordionItem>
      </AccordionRoot>

      اللوحة المغلقة hidden="until-found": بحث المتصفح أو رابط #id أو جزء نصي في العنوان يفتحها.

      كل الحالات، بدون تمرير الفأرة

      حالتان

      The panel of an open item is shown under its trigger.

      أو استورده من الحزمة

      topclassui/accordion
      import { AccordionRoot, AccordionItem } from 'topclassui/accordion'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      موقع الصفحة في الموقع، بروابط حقيقية ودون JavaScript. والمسار نفسه يُكتب BreadcrumbList بصيغة JSON-LD.

      تثبيت

      الشيفرة

      breadcrumb.tsx
      import { Breadcrumb } from 'topclassui/breadcrumb'
      
      /** The last item has no href: it is the page being read, and it stays out of the JSON-LD. */
      export default function Demo() {
        return (
          <Breadcrumb
            items={[
              { href: '/', label: 'Home' },
              { href: '/docs', label: 'Docs' },
              { label: 'Breadcrumb' },
            ]}
          />
        )
      }
      

      اترك href عن العنصر الأخير ليصبح الصفحة الحالية. العناصر ذات الروابط تُكتب أيضًا في BreadcrumbList بصيغة JSON-LD.

      كل الحالات، بدون تمرير الفأرة

      3 حالات

      أو استورده من الحزمة

      topclassui/breadcrumb
      import { Breadcrumb } from 'topclassui/breadcrumb'

      ثبّت مرة واحدة:npm i topclassui@beta zod

      أرقام صفحات هي روابط حقيقية لا معالجات نقر، فتعمل دون JavaScript ويتبع الزاحف كل صفحة منها.

      تثبيت

      جرّبه

      value
      pageCount
      siblingCount
      boundaryCount
      size

      الشيفرة

      pagination.tsx
      import { Pagination } from 'topclassui/pagination'
      
      <Pagination value={6} pageCount={12} getHref={(page) => `/blog?page=${String(page)}`} />

      getHref يبقي كل صفحة قابلة للزحف، وقيم value وsiblingCount وboundaryCount محصورة في مدى آمن.

      كل الحالات، بدون تمرير الفأرة

      4 حالات

      أو استورده من الحزمة

      topclassui/pagination
      import { Pagination } from 'topclassui/pagination'

      ثبّت مرة واحدة:npm i topclassui@beta zod