شريط إعلان
رسالة واحدة للصفحة كلها، بعرض كامل فوق الترويسة. يقع في تدفق الصفحة، فيدفعها إلى الأسفل ولا يغطي شيئًا.
split - الحجم لم يُقَس بعد
شريط إعلان
split - الحجم لم يُقَس بعدرسالة واحدة للصفحة كلها، بعرض كامل فوق الترويسة. يقع في تدفق الصفحة، فيدفعها إلى الأسفل ولا يغطي شيئًا.
Version 2 is out, with faster builds and a new theme editor.
Read the changelogجرّبه
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
Dismissible
أمثلة
- لرسالة واحدة يجب أن تراها الصفحة كلها: إصدار جديد، أو فترة تجريبية تنتهي، أو صيانة مجدولة. ضعه فوق الترويسة.
- الإجراء الذي هو رابط يكون زرًا مع
render={<a href="..." />}؛ الرابط المجرد بلا تنسيق وبلا مساحة لمس 44 بكسل. وإذا لم تتسع الرسالة والإجراء لسطر واحد ينتقل الإجراء تحت الرسالة. - مرّر
iconعندما تهمّ النبرة: اللون وحده لا يميّز التحذير من الإشعار العادي. dismissibleوidقيم عادية، فصفحة مكوّن خادم لا تحتاج إلى غلاف عميل، ولا يشحن الجزءَ العامل في المتصفح إلا الشريطُ القابل للإخفاء. أماonDismissفدالة، فلا يمررها إلا ملف عميل.- الخادم لا يقرأ تخزين الزائر، فالصفحة التالية تعرض الشريط المُخفى حتى يعمل السكربت فيزيله، فتصعد الصفحة تحته. لهذا يكون
dismissibleمعطّلًا افتراضيًا.
basic
Version 2 is out, with faster builds and a new theme editor.
Read the changelogbasic.tsx
import { bell } from 'topclassui/icons/bell'
import { Button } from 'topclassui/button'
import { Svg } from 'topclassui/svg'
import { Banner } from 'topclassui/banner'
/** The drawn banner: an icon, the message and a link, on the soft info tone. */
export default function Demo() {
return (
<Banner
tone="info"
aria-label="New version announcement"
icon={<Svg icon={bell} size="xs" />}
action={<Button size="sm" variant="outline" tone="info" render={<a href="/changelog" />}>Read the changelog</Button>}
>
Version 2 is out, with faster builds and a new theme editor.
</Banner>
)
}
tones
A new plan is available.
You are viewing an archived project.
Your domain is verified.
Your trial ends in three days.
The last payment failed.
Version 2 is out.
tones.tsx
import { info } from 'topclassui/icons/info'
import { Svg } from 'topclassui/svg'
import { Banner } from 'topclassui/banner'
const ICON = <Svg icon={info} size="xs" />
/** All six tones, each a landmark with a name of its own. */
export default function Demo() {
return (
<div className="flex flex-col gap-3">
<Banner tone="primary" aria-label="Primary banner" icon={ICON}>A new plan is available.</Banner>
<Banner tone="neutral" aria-label="Neutral banner" icon={ICON}>You are viewing an archived project.</Banner>
<Banner tone="success" aria-label="Success banner" icon={ICON}>Your domain is verified.</Banner>
<Banner tone="warning" aria-label="Warning banner" icon={ICON}>Your trial ends in three days.</Banner>
<Banner tone="danger" aria-label="Danger banner" icon={ICON}>The last payment failed.</Banner>
<Banner tone="info" aria-label="Info banner" icon={ICON}>Version 2 is out.</Banner>
</div>
)
}
with-action
Your trial ends in three days.
Add a payment methodThe last payment failed, so deploys are paused.
with-action.tsx
import { warning } from 'topclassui/icons/warning'
import { Button } from 'topclassui/button'
import { Svg } from 'topclassui/svg'
import { Banner } from 'topclassui/banner'
/** The action is a Button in the banner's own tone: a link through render, or a button. */
export default function Demo() {
return (
<div className="flex flex-col gap-3">
<Banner
tone="warning"
aria-label="Trial notice"
icon={<Svg icon={warning} size="xs" />}
action={<Button size="sm" tone="warning" render={<a href="/billing" />}>Add a payment method</Button>}
>
Your trial ends in three days.
</Banner>
<Banner
tone="danger"
aria-label="Payment notice"
action={<Button size="sm" variant="outline" tone="danger">Retry the payment</Button>}
>
The last payment failed, so deploys are paused.
</Banner>
<Banner
aria-labelledby="banner-plan-message"
action={<Button size="sm" variant="outline" render={<a href="/plans" />}>Compare plans</Button>}
>
<span id="banner-plan-message">A new plan is available.</span>
</Banner>
</div>
)
}
dismissible
Version 2 is out, with faster builds and a new theme editor.
Read the changelogScheduled maintenance starts on Sunday at 02:00 UTC.
dismissible.tsx
import { bell } from 'topclassui/icons/bell'
import { Button } from 'topclassui/button'
import { Svg } from 'topclassui/svg'
import { Banner } from 'topclassui/banner'
/** Two banners a visitor can dismiss, each remembered by its own id: the x hides one and leaves the other. */
export default function Demo() {
return (
<div className="flex flex-col gap-3">
<Banner
dismissible
id="release-v2"
tone="info"
aria-label="Release announcement"
icon={<Svg icon={bell} size="xs" />}
action={<Button size="sm" variant="outline" tone="info" render={<a href="/changelog" />}>Read the changelog</Button>}
>
Version 2 is out, with faster builds and a new theme editor.
</Banner>
<Banner dismissible id="maintenance-sunday" tone="warning" aria-label="Maintenance notice">
Scheduled maintenance starts on Sunday at 02:00 UTC.
</Banner>
</div>
)
}
minimal
Scheduled maintenance starts on Sunday at 02:00 UTC.
minimal.tsx
import { Banner } from 'topclassui/banner'
/** The message alone, on the default tone. */
export default function Demo() {
return <Banner aria-label="Maintenance window">Scheduled maintenance starts on Sunday at 02:00 UTC.</Banner>
}
long-action
Your workspace has used its monthly build minutes, so new deployments wait until the plan is upgraded.
Upgrade the workspace plan and resume deployments nowتجاوزت مساحة العمل دقائق البناء الشهرية، لذلك تنتظر عمليات النشر الجديدة حتى تتم ترقية الخطة.
long-action.tsx
import { warning } from 'topclassui/icons/warning'
import { Button } from 'topclassui/button'
import { Svg } from 'topclassui/svg'
import { Banner } from 'topclassui/banner'
/** A phone-wide box: a long action drops to a line of its own, so the message keeps a readable width. */
export default function Demo() {
return (
<div className="flex w-full max-w-80 flex-col gap-3">
<Banner
tone="warning"
aria-label="Build minutes notice"
icon={<Svg icon={warning} size="xs" />}
action={(
<Button size="sm" variant="outline" tone="warning" render={<a href="/billing" />}>
Upgrade the workspace plan and resume deployments now
</Button>
)}
>
Your workspace has used its monthly build minutes, so new deployments wait until the plan is upgraded.
</Banner>
<div dir="rtl" lang="ar">
<Banner
tone="info"
aria-label="إشعار دقائق البناء"
action={<Button size="sm" variant="outline" tone="info">ترقية خطة مساحة العمل واستئناف النشر الآن</Button>}
>
تجاوزت مساحة العمل دقائق البناء الشهرية، لذلك تنتظر عمليات النشر الجديدة حتى تتم ترقية الخطة.
</Banner>
</div>
</div>
)
}
long-text
The deploy is taking longer than usual while the static assets upload to the edge network.
Statushttps://example.com/projects/topclassui/deployments/2026-10-09/logs/build-step-four-of-six.txt
long-text.tsx
import { Button } from 'topclassui/button'
import { Banner } from 'topclassui/banner'
const LOG_URL = 'https://example.com/projects/topclassui/deployments/2026-10-09/logs/build-step-four-of-six.txt'
/** Two narrow boxes: the long message wraps above its action, and the unbroken URL breaks anywhere. */
export default function Demo() {
return (
<div className="flex flex-col gap-3">
<div className="w-64">
<Banner
tone="warning"
aria-label="Long notice"
action={<Button size="sm" variant="outline" tone="warning" render={<a href="/status" />}>Status</Button>}
>
The deploy is taking longer than usual while the static assets upload to the edge network.
</Banner>
</div>
<div className="w-64">
<Banner tone="danger" aria-label="Log address">{LOG_URL}</Banner>
</div>
</div>
)
}
بالعربية، من اليمين إلى اليسار
صدر الإصدار الثاني، مع بناء أسرع ومحرر جديد للسمات.
اقرأ المزيدتنتهي الفترة التجريبية بعد ثلاثة أيام.
rtl.tsx
import { bell } from 'topclassui/icons/bell'
import { Button } from 'topclassui/button'
import { Svg } from 'topclassui/svg'
import { Banner } from 'topclassui/banner'
/** Right to left: the icon at the start and the action at the end, with no physical class to mirror. */
export default function Demo() {
return (
<div dir="rtl" lang="ar" className="flex flex-col gap-3">
<Banner
tone="info"
aria-label="إعلان الإصدار"
icon={<Svg icon={bell} size="xs" />}
action={<Button size="sm" variant="outline" tone="info" render={<a href="/changelog" />}>اقرأ المزيد</Button>}
>
صدر الإصدار الثاني، مع بناء أسرع ومحرر جديد للسمات.
</Banner>
<Banner tone="warning" aria-label="تنبيه الفترة التجريبية">
تنتهي الفترة التجريبية بعد ثلاثة أيام.
</Banner>
</div>
)
}
الخصائص
لوحة المفاتيح وإمكانية الوصول
- شريط الإعلان معلَم من نوع
region، فيحتاج إلى اسم: مرّرaria-labelأوaria-labelledby. النوع يرفض شريطًا بلا أيٍّ منهما، والشريطان في صفحة واحدة يحتاجان إلى اسمين. - زر الإغلاق 24 بكسل، و44 بكسل على شاشة اللمس. وتحت الألوان القسرية يرسم الزر حدًّا عند التمرير، ويرسم الشريط حافة بدل تعبئته.
- الشريط القابل للإخفاء يحتاج إلى
idيفرضه النوع؛ وهو أيضًا معرّف العنصر.
من اليمين إلى اليسار
الأيقونة في البداية والإجراء في النهاية، وزر الإغلاق في نهاية السطر الذي يلتف إليه، دون أي صنف فيزيائي يحتاج إلى عكس.
الخادم والمتصفح
يُعرض على الخادم، والجزء التفاعلي مكوّن متصفح لا يُرسل إلا عند استخدامه.
الملفات: index.tsx, client.tsx.
على الشارة: split - الحجم لم يُقَس بعد.