COMPONENTS/OVERLAYS
Tooltip.
A few helpful words.
In practice
Wrap the tree with TooltipProvider. Tooltips supplement an accessible name; they do not replace labels.
Installation
Install Coal once. Components and TypeScript declarations are included. React 19 and React DOM 19 are peer dependencies.
Terminal · local package
npm install http://localhost:3100/downloads/chlohal-coal-ui-0.5.0.tgzThis installs the local package. It is not yet published on npm. See installation for stylesheet setup and integration.
Usage
example.tsx
"use client";
import * as React from "react";
import "@chlohal/coal-ui/styles.css";
import { Bell } from "lucide-react";
import { Button, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from "@chlohal/coal-ui";
export default function Example() {
return (<TooltipProvider>
<Tooltip>
<TooltipTrigger render={<Button size="icon" variant="outline" aria-label="Notifications"/>}>
<Bell size={16}/>
</TooltipTrigger>
<TooltipContent>Your notifications</TooltipContent>
</Tooltip>
</TooltipProvider>);
}
Source
The original Coal implementation. Use the package export to integrate it.
packages/react/src/tooltip.tsx
"use client";
import * as React from "react";
import { Action, cn, type ActionProps } from "./internal.js";
import {
FloatingRoot,
FloatingContent,
useFloating,
type FloatingContentProps,
type FloatingProps,
} from "./floating.js";
export function TooltipProvider({ children }: { children: React.ReactNode }) {
return <>{children}</>;
}
export function Tooltip(props: FloatingProps) {
return <FloatingRoot {...props} />;
}
export function TooltipTrigger({
onFocus,
onBlur,
onPointerEnter,
onPointerLeave,
onKeyDown,
...props
}: ActionProps) {
const c = useFloating();
return (
<Action
{...props}
ref={(node) => {
c.anchor.current = node;
}}
aria-describedby={c.open ? c.id : undefined}
onFocus={(e) => {
onFocus?.(e);
if (!e.defaultPrevented) {
c.cancelClose();
c.set(true);
}
}}
onBlur={(e) => {
onBlur?.(e);
c.scheduleClose();
}}
onPointerEnter={(e) => {
onPointerEnter?.(e);
if (e.pointerType !== "touch") {
c.cancelClose();
c.set(true);
}
}}
onPointerLeave={(e) => {
onPointerLeave?.(e);
c.scheduleClose();
}}
onKeyDown={(e) => {
onKeyDown?.(e);
if (e.key === "Escape") {
e.preventDefault();
c.set(false);
}
}}
/>
);
}
export function TooltipContent({
className,
onPointerEnter,
onPointerLeave,
...props
}: FloatingContentProps) {
const c = useFloating();
return (
<FloatingContent
onPointerEnter={(e) => {
c.cancelClose();
onPointerEnter?.(e);
}}
onPointerLeave={(e) => {
c.scheduleClose();
onPointerLeave?.(e);
}}
role="tooltip"
autoFocus={false}
className={cn("coal-tooltip", className)}
{...props}
/>
);
}
Accessibility checklist
- Provide an accessible name for controls, including icon-only buttons.
- Check keyboard navigation, visible focus and disabled states in your application.
- Do not rely on color alone to communicate status.