تلميح
سطر أو سطران من النص عند التمرير أو التركيز: اسم عنصر تحكم بأيقونة فقط، أو تسمية مقطوعة.
client - الحجم لم يُقَس بعد
تلميح
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
أمثلة
- ثلاثة أجزاء بأسماء مسطّحة،
TooltipRootوTooltipTriggerوTooltipPopup، ولا يوجدTooltipوحده. - كل ما فيه رابط أو عنصر تحكم هو نافذة منبثقة: أبناء النافذة مكتوبون كنص، فيُرفض العنصر عند الترجمة.
delayوcloseDelayعلى المشغّل، محصوران بين 0 و10000 مللي ثانية؛ إن لم يُمرَّرا يُطبَّق 600 و0، أو التأخير المشترك من مزوّد التطبيق.placementعلى النافذة، وtopافتراضيًا.- ضع نص المشغّل أو أيقونته داخل الزر الممرَّر إلى
render، لا داخلTooltipTrigger، فتبقى التسمية تنتهي بعلامة حذف وتفسح الأيقونة مكانها لمؤشر التحميل.
basic
basic.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'
/** The drawn sample: an icon-only ghost Button whose aria-label repeats the tooltip text,
* because touch never shows a tooltip. The icon sits inside the Button, not the trigger,
* so a Server Component keeps it beside a loading spinner. It opens above, the default. */
export default function Demo() {
return (
<TooltipRoot>
<TooltipTrigger
render={
<Button variant="ghost" aria-label="Copy link">
<Svg icon={linkSimple} />
</Button>
}
/>
<TooltipPopup>Copy link</TooltipPopup>
</TooltipRoot>
)
}
delays
delays.tsx
import { copy } from 'topclassui/icons/copy'
import { gear } from 'topclassui/icons/gear'
import { trash } from 'topclassui/icons/trash'
import { Button } from 'topclassui/button'
import { Svg } from 'topclassui/svg'
import { TooltipPopup, TooltipRoot, TooltipTrigger } from 'topclassui/tooltip'
/** A toolbar of three icon-only Buttons: Copy opens at once, Delete waits Base UI's
* 600 ms because it passes no delay, and Settings stays 300 ms after the pointer leaves. */
export default function Demo() {
return (
<div className="flex flex-wrap items-center gap-2">
<TooltipRoot>
<TooltipTrigger
delay={0}
render={
<Button variant="ghost" aria-label="Copy">
<Svg icon={copy} />
</Button>
}
/>
<TooltipPopup>Copy</TooltipPopup>
</TooltipRoot>
<TooltipRoot>
<TooltipTrigger
render={
<Button variant="ghost" aria-label="Delete this row">
<Svg icon={trash} />
</Button>
}
/>
<TooltipPopup placement="bottom">Delete this row</TooltipPopup>
</TooltipRoot>
<TooltipRoot>
<TooltipTrigger
closeDelay={300}
render={
<Button variant="ghost" aria-label="Settings">
<Svg icon={gear} />
</Button>
}
/>
<TooltipPopup>Settings</TooltipPopup>
</TooltipRoot>
</div>
)
}
long-label
long-label.tsx
import { Button } from 'topclassui/button'
import { TooltipPopup, TooltipRoot, TooltipTrigger } from 'topclassui/tooltip'
const LONG = 'Save this document and continue to the next step of the wizard'
const FILE = 'quarterly-report-final-v2-reviewed-by-legal-and-finance.pdf'
/** Why Tooltip is in Unit 1: each Button truncates its label in a narrow box, and the
* tooltip shows it whole. The label is inside the Button, so a server render keeps its
* truncating span. The sentence wraps at max-w-xs; the file name breaks anywhere. */
export default function Demo() {
return (
<div className="flex flex-col gap-3">
<div className="w-50 rounded-box border border-line p-2">
<TooltipRoot>
<TooltipTrigger render={<Button>{LONG}</Button>} />
<TooltipPopup>{LONG}</TooltipPopup>
</TooltipRoot>
</div>
<div className="w-50 rounded-box border border-line p-2">
<TooltipRoot>
<TooltipTrigger render={<Button variant="outline">{FILE}</Button>} />
<TooltipPopup placement="bottom-start">{FILE}</TooltipPopup>
</TooltipRoot>
</div>
</div>
)
}
with-count
with-count.tsx
import { trash } from 'topclassui/icons/trash'
import { Button } from 'topclassui/button'
import { Svg } from 'topclassui/svg'
import { TooltipPopup, TooltipRoot, TooltipTrigger } from 'topclassui/tooltip'
const COUNT = 3
/** An interpolated tooltip, which JSX passes as an array of text: the popup takes it,
* and the aria-label spells out the same words for the icon-only Button. */
export default function Demo() {
return (
<TooltipRoot>
<TooltipTrigger
render={
<Button variant="soft" tone="danger" aria-label={`Delete ${String(COUNT)} rows`}>
<Svg icon={trash} />
</Button>
}
/>
<TooltipPopup>Delete {COUNT} rows</TooltipPopup>
</TooltipRoot>
)
}
placements
placements.tsx
import { Button } from 'topclassui/button'
import { TooltipPopup, TooltipRoot, TooltipTrigger } from 'topclassui/tooltip'
import type { TooltipPlacement } from 'topclassui/tooltip'
const PLACES: TooltipPlacement[] = [
'top-start', 'top', 'top-end',
'start-top', 'start', 'start-bottom',
'end-top', 'end', 'end-bottom',
'bottom-start', 'bottom', 'bottom-end',
]
/** All twelve placements, one outline Button each. The label names the placement and
* the tooltip shows the same words, so the trigger's name carries the text. */
export default function Demo() {
return (
<div className="grid grid-cols-3 gap-3 p-12">
{PLACES.map((place) => (
<TooltipRoot key={place}>
<TooltipTrigger render={<Button variant="outline" size="sm">{place}</Button>} />
<TooltipPopup placement={place}>{place}</TooltipPopup>
</TooltipRoot>
))}
</div>
)
}
disabled
disabled.tsx
import { pencilSimple } from 'topclassui/icons/pencil-simple'
import { Button } from 'topclassui/button'
import { Svg } from 'topclassui/svg'
import { TooltipPopup, TooltipRoot, TooltipTrigger } from 'topclassui/tooltip'
/** TooltipRoot disabled: the Button still works and its aria-label still names it, but
* no tooltip opens on hover or focus. Base UI takes the prop untouched. */
export default function Demo() {
return (
<TooltipRoot disabled>
<TooltipTrigger
render={
<Button variant="outline" aria-label="Rename">
<Svg icon={pencilSimple} />
</Button>
}
/>
<TooltipPopup>Rename</TooltipPopup>
</TooltipRoot>
)
}
بالعربية، من اليمين إلى اليسار
rtl.tsx
import { linkSimple } from 'topclassui/icons/link-simple'
import { trash } from 'topclassui/icons/trash'
import { TopClassProvider } from 'topclassui/provider'
import { Button } from 'topclassui/button'
import { Svg } from 'topclassui/svg'
import { TooltipPopup, TooltipRoot, TooltipTrigger } from 'topclassui/tooltip'
/** Arabic, inside TopClassProvider as the root layout would mount it: Base UI mirrors
* start and end from the provider, so start opens on the right and end on the left. */
export default function Demo() {
return (
<TopClassProvider direction="rtl" locale="ar">
<div dir="rtl" lang="ar" className="flex flex-wrap items-center gap-3">
<TooltipRoot>
<TooltipTrigger
render={
<Button variant="ghost" aria-label="نسخ الرابط">
<Svg icon={linkSimple} />
</Button>
}
/>
<TooltipPopup placement="start">نسخ الرابط</TooltipPopup>
</TooltipRoot>
<TooltipRoot>
<TooltipTrigger
render={
<Button variant="ghost" aria-label="حذف هذا الصف">
<Svg icon={trash} />
</Button>
}
/>
<TooltipPopup placement="end">حذف هذا الصف</TooltipPopup>
</TooltipRoot>
</div>
</TopClassProvider>
)
}
الخصائص
TooltipRoot
لا خصائص خاصة به: يأخذ سمات العنصر الذي يعرضه.
TooltipPopup
TooltipTrigger
لوحة المفاتيح وإمكانية الوصول
- لا يربط Base UI النافذة بأي عنصر، فاسم المشغّل هو الذي يحمل النص، لا التلميح.
- أبناء النافذة مكتوبون كنص: العنصر أو الرابط أو عنصر التحكم يُرفض عند الترجمة.
من اليمين إلى اليسار
start يفتح على اليمين وend على اليسار. الموضع الافتراضي top يبقى في الأعلى.
الخادم والمتصفح
مكوّن متصفح: يُعرض على الخادم ثم يُرطَّب في المتصفح.
الملفات: index.tsx, client.tsx.
على الشارة: client - الحجم لم يُقَس بعد.