ComponentsTooltip
Tooltip
Show a short hint when users hover over or focus a control.
On this page
Install component source from the public registry, or use the local workspace package. Follow the setup guide first. The npm package is not published yet.
View registry files- React Aria
(react-aria)Accessibility hooks and overlay utilities used by the implementation.
- React Aria Components
(react-aria-components)Accessible interaction primitives, including keyboard behavior, focus handling, and ARIA semantics.
Shared foundation: React, clsx for conditional classes, tailwind-merge for resolving utility-class conflicts. Styles use Tailwind CSS and Dethink CSS variables.
Based on this component’s source and registry composition. Libraries used only in showcase examples are excluded.
Import the component into your page or component file.
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@dethink/components";Try the examples, then open the code to use them in your app. Tab to a trigger — tooltips show on focus too.
Basic
An icon-only trigger keeps its aria-label; the tooltip adds the visible hint.
Show sourceexamples/tooltip/basic.tsx
"use client";
import { Tooltip, TooltipContent, TooltipTrigger } from "@dethink/components";
import { RefreshCw } from "lucide-react";
export function TooltipBasic() {
return (
<div className="flex justify-center">
<Tooltip>
<TooltipTrigger
aria-label="Refresh dashboard"
size="icon"
variant="outline"
>
<RefreshCw className="size-4" aria-hidden="true" />
</TooltipTrigger>
<TooltipContent>Refresh dashboard data</TooltipContent>
</Tooltip>
</div>
);
}Timing and placement
delay and closeDelay tune hover intent; placement and showArrow position the hint.
Show sourceexamples/tooltip/timing.tsx
"use client";
import { Tooltip, TooltipContent, TooltipTrigger } from "@dethink/components";
export function TooltipTiming() {
return (
<div className="flex flex-wrap justify-center gap-3">
<Tooltip delay={0} closeDelay={0}>
<TooltipTrigger variant="soft" size="sm">
Instant
</TooltipTrigger>
<TooltipContent>Shows immediately</TooltipContent>
</Tooltip>
<Tooltip delay={700} closeDelay={300}>
<TooltipTrigger variant="soft" size="sm">
Patient
</TooltipTrigger>
<TooltipContent>700ms open delay, 300ms close delay</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger variant="soft" size="sm">
Placed top
</TooltipTrigger>
<TooltipContent placement="top" showArrow>
Anchored above with an arrow
</TooltipContent>
</Tooltip>
</div>
);
}Examples that combine components for common tasks.
Formatting toolbar with shortcut hints
Tooltips in their strongest seat: an icon-only toolbar where each hint pairs the action name with its keyboard shortcut, while aria-label and aria-pressed keep the buttons fully accessible without the tooltip.
Show sourceexamples/tooltip/recipe-toolbar.tsx
"use client";
import { useState } from "react";
import { Tooltip, TooltipContent, TooltipTrigger } from "@dethink/components";
import { Bold, Italic, Link2, Strikethrough } from "lucide-react";
const tools = [
{ id: "bold", label: "Bold", keys: "⌘B", icon: Bold },
{ id: "italic", label: "Italic", keys: "⌘I", icon: Italic },
{ id: "strike", label: "Strikethrough", keys: "⌘⇧X", icon: Strikethrough },
{ id: "link", label: "Add link", keys: "⌘K", icon: Link2 },
];
/**
* Icon-only toolbars are where tooltips earn their keep: each trigger keeps
* a real aria-label (the tooltip is a hint, not the accessible name) and the
* content pairs the label with its keyboard shortcut.
*/
export function TooltipRecipeToolbar() {
const [active, setActive] = useState<Set<string>>(new Set(["bold"]));
return (
<div
role="toolbar"
aria-label="Text formatting"
className="border-border bg-muted/40 mx-auto flex w-fit gap-1 rounded-lg border p-1"
>
{tools.map((tool) => (
<Tooltip key={tool.id} delay={300}>
<TooltipTrigger
aria-label={tool.label}
aria-pressed={active.has(tool.id)}
size="icon"
variant={active.has(tool.id) ? "soft" : "ghost"}
onClick={() =>
setActive((current) => {
const next = new Set(current);
if (next.has(tool.id)) {
next.delete(tool.id);
} else {
next.add(tool.id);
}
return next;
})
}
>
<tool.icon className="size-4" aria-hidden="true" />
</TooltipTrigger>
<TooltipContent placement="top">
<span className="flex items-center gap-2">
{tool.label}
<kbd className="border-border/60 rounded border px-1 font-mono text-[0.7em]">
{tool.keys}
</kbd>
</span>
</TooltipContent>
</Tooltip>
))}
</div>
);
}Tooltip coordinates timing; the trigger is a real Button and the content carries placement.
| Prop | What it does | Default |
|---|---|---|
delay / closeDelaynumber (ms) | Hover intent timing before showing and hiding. | library defaults |
open / onOpenChangeboolean / (open) => void | Controlled visibility for programmatic tooltips. | Not set |
disabledboolean | Suppresses the tooltip without disabling the trigger. | false |
TooltipTriggervariant + size (Button API) | A real button trigger — keep the accessible name on the trigger (aria-label); the tooltip is a hint, not the name. | Not set |
TooltipContent — placement"top" | "bottom" | "left" | "right" (+ alignment) | Preferred side relative to the trigger. | "top" |
TooltipContent — showArrowboolean | Renders a pointing arrow. | false |