Next.js Bootstrap Tooltips
A Next.js Bootstrap tooltip for the App Router: wrap an element in a client component for a tooltip on hover and focus, positioned by Floating UI.
This component is only available in AdminKit PRO. Learn more.
Tooltips give a short hint about an element when the user hovers over it or moves the focus to it: what an icon button does, or a detail that does not fit in the label. Tooltip wraps one element and adds Bootstrap's tooltip to it. Floating UI positions the tooltip and Bootstrap's CSS styles it, without Bootstrap's JavaScript or Popper. Tooltips are part of the PRO version of AdminKit for Next.js.
In the App Router, it matters where you write the tooltip. Tooltip is a client component, a file that starts with "use client". It clones its child element to attach its handlers and ref. Pages are server components, though: they render on the server. An element that a server component creates reaches the client component in a form it cannot clone. So Tooltip throws an error there: "Tooltip and Popover clone their child element: create it in a client component". Put the Tooltip and its child in a client component, and render that from your page.
Example
"use client";
import { Tooltip } from "@/components/bootstrap/overlay";
const placements = ["left", "top", "bottom", "right"] as const;
export function TooltipButtons() {
return placements.map((placement) => (
<Tooltip key={placement} content={`Tooltip on ${placement}`} placement={placement}>
<button type="button" className="btn btn-secondary me-2 mb-2">
Tooltip on {placement}
</button>
</Tooltip>
));
}The page stays a server component:
import { TooltipButtons } from "@/components/tooltip-buttons";
import { pageMetadata } from "@/lib/site";
export const metadata = pageMetadata("/ui-general");
export default function Page() {
return (
<div className="card">
<div className="card-body">
<TooltipButtons />
</div>
</div>
);
}The server HTML has the buttons only. The tooltip renders in a portal on document.body after hydration, once the browser has taken over that HTML. That way the server and the browser agree on the markup. When the chosen side has no room, the tooltip flips to the other side. It stays 8px from the edges of the window.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
content | ReactNode | The text of .tooltip-inner | |
placement | "top" | "bottom" | "left" | "right" | "top" | The side of the element it appears on |
trigger | ("hover" | "focus" | "click")[] | ["hover", "focus"] | The events that show it |
children | ReactElement | One element, created in a client component |
The child gets a ref, the trigger handlers and aria-describedby. It must be an HTML element or a component that passes ref and the other props on to one. Its own handlers, such as onClick, keep working. The component is in src/components/bootstrap/overlay.tsx.
HTML content
When plain text is not enough, pass markup. content is a React node, so it can hold formatting:
<Tooltip
content={
<>
<em>Tooltip</em> <u>with</u> <b>HTML</b>
</>
}
>
<button type="button" className="btn btn-secondary">Tooltip with HTML</button>
</Tooltip>Disabled elements
A tooltip is a good place to say why a button is disabled. But a disabled button receives no mouse or focus events, so put the tooltip on a focusable span around it:
<Tooltip content="Upgrade to export">
<span className="d-inline-block" tabIndex={0}>
<button type="button" className="btn btn-primary" disabled>Export CSV</button>
</span>
</Tooltip>Accessibility
- The tooltip has
role="tooltip". While it shows, the element hasaria-describedbypointing at it, so screen readers read it as the element's description. - A description does not replace a name: an icon-only button still needs an
aria-label. - The tooltip shows on focus, so keyboard users get it too, as long as the element can take the focus (a button, a link or
tabIndex={0}). Escape hides it. - Keep it to short text. It hides when the pointer leaves the element, so links in it cannot be reached. Use a popover instead.
Related
- React Bootstrap tooltips: the same component in AdminKit for React (Vite)
- Bootstrap 5 tooltips: the tooltips of the HTML version
- Popovers: a larger overlay that opens on click
- General UI demo
Last updated on
ToastsPro
Next.js toast notifications for the App Router: a ToastProvider in the root layout and a useToast() hook for client components, built on Bootstrap's toast.
TabsPro
Next.js Bootstrap tabs for the App Router: client components a server component page renders directly, with keyboard support and vertical or colored styles.