Qure UI
Components

Popover

A small panel anchored to the control that opened it, for detail that would clutter the page if it were always there.

'use client'import { Button } from '@/registry/qure/ui/button'import {  Popover, PopoverContent, PopoverDescription, PopoverHeader,  PopoverTitle, PopoverTrigger,} from '@/registry/qure/ui/popover'export default function PopoverDemo() {  return (    <Popover>      <PopoverTrigger render={<Button variant="tertiary">ACC-4471902</Button>} />      <PopoverContent>        <PopoverHeader>          <PopoverTitle>CT Thorax, contrast</PopoverTitle>          <PopoverDescription>            Acquired 14 March 2026, 09:12. Reported by Dr A. Rao.          </PopoverDescription>        </PopoverHeader>        <dl className="grid grid-cols-[auto_1fr] gap-x-4 gap-y-1 text-sm">          <dt className="text-muted-foreground">Slices</dt>          <dd>412</dd>          <dt className="text-muted-foreground">Series</dt>          <dd>4</dd>          <dt className="text-muted-foreground">Priors</dt>          <dd>2</dd>        </dl>      </PopoverContent>    </Popover>  )}

Installation

npx shadcn@latest add https://qure-ui.qure.ai/r/popover.json

Usage

import {
  Popover, PopoverContent, PopoverDescription, PopoverHeader,
  PopoverTitle, PopoverTrigger,
} from '@/components/ui/popover'
<Popover>
  <PopoverTrigger render={<Button variant="tertiary">ACC-4471902</Button>} />
  <PopoverContent>
    <PopoverHeader>
      <PopoverTitle>CT Thorax, contrast</PopoverTitle>
      <PopoverDescription>Acquired 14 March 2026, 09:12.</PopoverDescription>
    </PopoverHeader>
  </PopoverContent>
</Popover>

A popover is for detail the reader asks for. If the content is a single phrase and needs no interaction, use a Tooltip; if it demands a decision before anything else can continue, use a Dialog. A popover sits between the two: dismissible, non-blocking, and able to hold controls.

Composition

<Popover>              {/* owns the open state */}
  <PopoverTrigger>     {/* the anchor as well as the button */}
  <PopoverContent>     {/* portal + positioner + popup, in one */}
    <PopoverHeader>    {/* title and description, 4px apart */}
      <PopoverTitle>       {/* labels the popup for assistive tech */}
      <PopoverDescription> {/* describes it */}
    </PopoverHeader>
    <PopoverFooter>    {/* actions, right-aligned */}
      <PopoverClose>   {/* closes without a state hook */}

PopoverContent collapses three Base UI parts. The portal takes the popup out of the local stacking context, the positioner does the anchoring and publishes --transform-origin, --anchor-width and --available-height, and the popup is the surface. Keeping them together means a demo never has to name the positioner, and the stylesheet can still read those variables because the popup inherits them.

PopoverTitle is not decoration: Base UI wires it to the popup's aria-labelledby. A popover with a heading that is a plain <div> announces as an unnamed group.

Anchoring

'use client'import { Button } from '@/registry/qure/ui/button'import { Popover, PopoverContent, PopoverDescription, PopoverTrigger } from '@/registry/qure/ui/popover'const sides = ['top', 'right', 'bottom', 'left'] as constexport default function PopoverSide() {  return (    <div className="flex flex-wrap items-center justify-center gap-2">      {sides.map(side => (        <Popover key={side}>          <PopoverTrigger render={<Button variant="tertiary" size="sm">{side}</Button>} />          <PopoverContent side={side} className="w-56">            <PopoverDescription>              Anchored to the {side}. It flips to the opposite side when the viewport runs out.            </PopoverDescription>          </PopoverContent>        </Popover>      ))}    </div>  )}

side and align are the preferences, not the outcome — the popover flips or shifts when the viewport is out of room. Reach for side="right" in a viewer, where the study is the thing you must not cover.

With a form

'use client'import { Button } from '@/registry/qure/ui/button'import { Input } from '@/registry/qure/ui/input'import { Label } from '@/registry/qure/ui/label'import {  Popover, PopoverClose, PopoverContent, PopoverFooter,  PopoverHeader, PopoverTitle, PopoverTrigger,} from '@/registry/qure/ui/popover'export default function PopoverForm() {  return (    <Popover>      <PopoverTrigger render={<Button variant="secondary">Add a note</Button>} />      <PopoverContent className="w-80">        <PopoverHeader>          <PopoverTitle>Note on ACC-4471902</PopoverTitle>        </PopoverHeader>        <div className="flex flex-col gap-2">          <Label htmlFor="popover-note">Note</Label>          <Input id="popover-note" placeholder="Nodule unchanged since March" />        </div>        <PopoverFooter>          <PopoverClose render={<Button variant="tertiary" size="sm">Cancel</Button>} />          <PopoverClose render={<Button size="sm">Save</Button>} />        </PopoverFooter>      </PopoverContent>    </Popover>  )}

A popover can hold controls, which a tooltip cannot. Focus moves to the first tabbable element when it opens and returns to the trigger when it closes, so a note can be typed and saved without touching the mouse.

With an arrow and a close button

'use client'import { Button } from '@/registry/qure/ui/button'import {  Popover, PopoverContent, PopoverDescription, PopoverHeader,  PopoverTitle, PopoverTrigger,} from '@/registry/qure/ui/popover'export default function PopoverArrow() {  return (    <Popover>      <PopoverTrigger render={<Button variant="tertiary">Why was this flagged?</Button>} />      <PopoverContent showArrow showCloseButton className="w-80">        <PopoverHeader>          <PopoverTitle>Suspected pneumothorax</PopoverTitle>          <PopoverDescription>            qXR marked the right apex with a confidence of 0.86. The finding is advisory and does            not replace a read.          </PopoverDescription>        </PopoverHeader>      </PopoverContent>    </Popover>  )}

The arrow earns its place when several triggers sit close together and the popover would otherwise be ambiguous. The close button is worth adding when the content is long enough that the trigger has scrolled out of sight.

This is also the shape to reach for when explaining a model output: confidence figures and provenance belong behind a popover rather than in the table, because a radiologist reads the row and asks for the reasoning only when the row surprises them.

A popover opened on hover is a tooltip with extra steps — the content becomes unreachable for anyone who cannot hold a pointer still. openOnHover exists on PopoverTrigger, but if you find yourself wanting it, the content probably belongs in a Tooltip.

Keyboard

Enter or Space on the trigger opens it, Escape closes it and returns focus, Tab cycles within the popup while it is open. None of that is written here — it arrives with the primitive.

API Reference

Everything Base UI's Popover accepts. What we add on PopoverContent:

Prop

Type

On Popover itself, the ones you will reach for:

Prop

Type

On this page