Tooltip
Hover label with delay and side placement control. Supports rich content including Kbd.
Examples
Placement
Anchor the tooltip to any side of the trigger.
import { Button } from "@codefast/ui/button";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@codefast/ui/tooltip";
export function TooltipSides() {
return (
<TooltipProvider>
<div className="flex flex-wrap gap-2">
{(["left", "top", "bottom", "right"] as const).map((side) => (
<Tooltip key={side}>
<TooltipTrigger asChild>
<Button variant="outline" className="w-fit capitalize">
{side}
</Button>
</TooltipTrigger>
<TooltipContent side={side}>
<p>Add to library</p>
</TooltipContent>
</Tooltip>
))}
</div>
</TooltipProvider>
);
}
Disabled Button
Show a tooltip on a disabled button by wrapping it with a span.
import { Button } from "@codefast/ui/button";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@codefast/ui/tooltip";
export function TooltipDisabled() {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<span className="inline-block w-fit">
<Button variant="outline" disabled>
Disabled
</Button>
</span>
</TooltipTrigger>
<TooltipContent>
<p>This feature is currently unavailable</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}
With Keyboard Shortcut
A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.
import { Button } from "@codefast/ui/button";
import { Kbd } from "@codefast/ui/kbd";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@codefast/ui/tooltip";
import { SaveIcon } from "lucide-react";
export function TooltipKeyboard() {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline" size="icon-sm">
<SaveIcon />
</Button>
</TooltipTrigger>
<TooltipContent>
Save Changes <Kbd>S</Kbd>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}
RTL
Right-to-left layout support for languages such as Arabic and Hebrew.
Translations are AI-generated for demonstration and may be imperfect.
import { Button } from "@codefast/ui/button";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@codefast/ui/tooltip";
import type { Translations } from "#/features/components-catalog/components/detail/language";
import { useTranslation } from "#/features/components-catalog/components/detail/language-context";
const translations: Translations = {
en: {
dir: "ltr",
values: {
content: "Add to library",
left: "Left",
top: "Top",
bottom: "Bottom",
right: "Right",
},
},
ar: {
dir: "rtl",
values: {
content: "إضافة إلى المكتبة",
left: "يسار",
top: "أعلى",
bottom: "أسفل",
right: "يمين",
},
},
he: {
dir: "rtl",
values: {
content: "הוסף לספרייה",
left: "שמאל",
top: "למעלה",
bottom: "למטה",
right: "ימין",
},
},
};
const sides = ["left", "top", "bottom", "right"] as const;
export function TooltipRtl() {
const { t } = useTranslation(translations, "ar");
return (
<TooltipProvider>
<div className="flex flex-wrap gap-2">
{sides.map((side) => (
<Tooltip key={side}>
<TooltipTrigger asChild>
<Button variant="outline" className="w-fit capitalize">
{t[side]}
</Button>
</TooltipTrigger>
<TooltipContent side={side}>{t.content}</TooltipContent>
</Tooltip>
))}
</div>
</TooltipProvider>
);
}
Usage
The minimal import and composition — see Examples below for styled, real-world variants.
import { Button } from "@codefast/ui/button";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@codefast/ui/tooltip";
export function TooltipUsage() {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">Hover me</Button>
</TooltipTrigger>
<TooltipContent>
<p>Add to library</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}
Anatomy
How the parts nest — every slot the component exposes, in composition order.
Features
- TooltipContent always renders its own arrow — no separate TooltipArrow needs to be added, unlike Popover or DropdownMenu.
- Drop a Kbd inside TooltipContent to show a keyboard shortcut; it gets its own spacing and isolation styling automatically.
API reference
Props for each part of the component. All native element props are also forwarded.
TooltipProvider
Wrap your app (or a region) once; shares timing across tooltips.
delayDurationnumberMilliseconds to hover before the tooltip opens — codefast overrides Radix's 700ms default to open instantly.
Default
0skipDelayDurationnumberWindow in which moving between triggers skips the delay.
Default
300
TooltipContent
side"top" | "right" | "bottom" | "left"Preferred side relative to the trigger.
Default
"top"sideOffsetnumberDistance in px between the trigger and the content.
Default
0
Accessibility
Built to be keyboard-navigable and screen-reader friendly out of the box.
| Key | Function |
|---|---|
| Tab | Focusing the trigger opens the tooltip. |
| Esc | Closes the open tooltip. |
- The trigger must be a focusable element — use asChild over a Button or link.
- Tooltips are supplementary: never put essential information or actions inside one.
- Content is linked to the trigger via aria-describedby for screen readers.
Guidelines
Conventions that keep usage consistent across an app.
Do
- Keep tooltip text to a short phrase.
- Use for naming icon-only controls and surfacing shortcuts.
Don’t
- Don’t place interactive controls inside a tooltip — use a Popover.
- Don’t hide information the user needs to complete a task.
Explore further
Ready to integrate?
Follow the Getting Started guide to install @codefast/ui, or browse the full component gallery.