Next.js Bootstrap Popovers
A Next.js Bootstrap popover for App Router client components: a title and body that open on click beside an element and render only in the browser.
This component is only available in AdminKit PRO. Learn more.
When a tooltip is too small for what you want to say, use a popover. It is an overlay with an optional title and a body, and it opens when the user clicks the element it wraps. Floating UI places the popover and Bootstrap's CSS styles it, without Bootstrap's JavaScript or Popper. Popovers are part of the PRO version of AdminKit for Next.js.
In the App Router, pages are server components: they render on the server. Popover is a client component, and it clones its child element to attach its click handler. A child created in a server component cannot be cloned, so Popover throws "Tooltip and Popover clone their child element: create it in a client component". Write the Popover and its child in a client component, a file that starts with "use client", and render that from the page.
Example
"use client";
import { Popover } from "@/components/bootstrap/overlay";
export function BillingHint() {
return (
<Popover title="Billing" content="Invoices are sent on the 1st of every month.">
<button type="button" className="btn btn-info">Billing details</button>
</Popover>
);
}The page renders it as a regular component:
import { BillingHint } from "@/components/billing-hint";
import { pageMetadata } from "@/lib/site";
export const metadata = pageMetadata("/pages-settings");
export default function Page() {
return (
<>
<h1 className="h3 mb-3">Settings</h1>
<BillingHint />
</>
);
}The popover opens to the right of the button. A second click closes it, and so do Escape and a click outside both the button and the popover. The popover renders in a portal on document.body, and only after hydration, when the browser has taken over the page. So the server HTML holds the button alone.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | ReactNode | The .popover-header (an h3); left out when empty | |
content | ReactNode | The .popover-body | |
placement | "top" | "bottom" | "left" | "right" | "right" | The side of the element it appears on |
trigger | ("hover" | "focus" | "click")[] | ["click"] | The events that open it |
children | ReactElement | One element, created in a client component |
The child receives a ref, the trigger handlers and aria-describedby, so it must be an HTML element or a component that passes them on to one. Its own handlers keep running. The click trigger prevents the click's default action: a link as the child does not navigate.
The component is in src/components/bootstrap/overlay.tsx, together with Tooltip.
Four directions
Choose the side with placement. When that side has no room, the popover flips to the opposite one. It keeps 8px from the edges of the window. The demo's general UI page renders these buttons from a client component, src/components/pages/ui/general/overlay-demos.tsx.
"use client";
import { Popover } from "@/components/bootstrap/overlay";
const placements = [
{ placement: "top", text: "Opens above the button." },
{ placement: "bottom", text: "Opens below the button." },
{ placement: "left", text: "Opens to the left of the button." },
{ placement: "right", text: "Opens to the right of the button." },
] as const;
export function PopoverButtons() {
return placements.map(({ placement, text }) => (
<Popover key={placement} title={`Popover on ${placement}`} content={text} placement={placement}>
<button type="button" className="btn btn-secondary me-2 mb-2">
Popover on {placement}
</button>
</Popover>
));
}Hover and focus
A popover can also open the way a tooltip does. With trigger={["hover", "focus"]}, it opens while the pointer is over the element or the element has the focus. A disabled button gets neither, so wrap it in a focusable span:
<Popover
title="Locked"
content="This invoice has been paid."
trigger={["hover", "focus"]}
>
<span className="d-inline-block" tabIndex={0}>
<button type="button" className="btn btn-primary" disabled>Edit invoice</button>
</span>
</Popover>Accessibility
- The popover has
role="tooltip", and while it is open,aria-describedbyon the element points at it. - Opening the popover does not move the focus, and the popover is at the end of
document.body. Keep its content to text. For links, buttons or fields, use a dropdown or a modal. - Escape closes it. Use a button, or an element with
tabIndex={0}, as the child so keyboard users can open it.
Related
- React Bootstrap popovers: the same component in AdminKit for React (Vite)
- Bootstrap 5 popovers: the popovers of the HTML version
- Tooltips: a short text on hover and focus
- General UI demo
Last updated on
PlaceholdersPro
Next.js Bootstrap placeholders in AdminKit PRO: loading cards in the static HTML, swapped for data fetched in a client component, with sizes and animation.
ProgressPro
A Next.js Bootstrap progress bar in AdminKit PRO: server-rendered quotas, a live value from client state, aria-valuenow, labels, colors and stacked bars.