Popover
A floating panel that appears next to a trigger element. Useful for tooltips with rich content, contextual menus, additional details, or any supplementary information that should appear on demand.
Example
A simple popover with a title and description.
<div buiPopover>
<button matButton buiPopoverTrigger>Open Popover</button>
<ng-template buiPopoverPortal>
<div buiPopoverContent>
<h3 buiPopoverTitle>Dimensions</h3>
<p buiPopoverDescription>
Set the dimensions for the layer. Width and height
can be adjusted independently.
</p>
</div>
</ng-template>
</div>Structure
The popover is fully directive-based. You compose it by applying attribute directives to standard HTML elements.
<div buiPopover>
<button matButton buiPopoverTrigger>Open</button>
<ng-template buiPopoverPortal>
<div buiPopoverContent>
<h3 buiPopoverTitle>Title</h3>
<p buiPopoverDescription>Description</p>
<button matButton buiPopoverClose>Close</button>
</div>
</ng-template>
</div>
<!-- With an external anchor -->
<span buiPopoverAnchor #myAnchor="buiPopoverAnchor">
Anchor
</span>
<div buiPopover [anchor]="myAnchor">
<button matButton buiPopoverTrigger>Open</button>
<ng-template buiPopoverPortal>
<div buiPopoverContent>
<h3 buiPopoverTitle>Title</h3>
<p buiPopoverDescription>Description</p>
<button matButton buiPopoverClose>Close</button>
</div>
</ng-template>
</div>The building blocks are:
| Directive | Description |
|---|---|
buiPopover | Root container. Manages open state, anchor positioning, and the CDK overlay. |
buiPopoverTrigger | Opens the popover when clicked. Also serves as the default positioning anchor unless an external anchor is provided. |
buiPopoverAnchor | Marks an element as the positioning anchor for the popover, allowing the overlay to be positioned relative to a different element than the trigger. Optional. |
buiPopoverPortal | Wraps the content that is rendered inside a CDK overlay when the popover opens. |
buiPopoverContent | The floating panel itself. Handles entry/exit animations. |
buiPopoverClose | Closes the popover when clicked. |
buiPopoverTitle | Title text inside the content. Connects to aria-labelledby. Optional. |
buiPopoverDescription | Description text inside the content. Connects to aria-describedby. Optional. |
buiPopover
The root directive. Apply it to any element to create a popover instance. It manages the open state, positions the overlay relative to the trigger, and handles dismissal via backdrop click or Escape key.
<!-- Default (bottom) -->
<div buiPopover>...</div>
<!-- Custom position -->
<div buiPopover position="top-start">...</div>
<!-- Custom offset -->
<div buiPopover [offset]="8">...</div>
<!-- Two-way open binding -->
<div buiPopover [(open)]="isOpen">...</div>
<!-- Close on scroll -->
<div buiPopover [closeOnScroll]="true">...</div>
<!-- External anchor -->
<div buiPopover [anchor]="myAnchor">...</div>| Prop | Type | Default | Description |
|---|---|---|---|
open | model<boolean> | false | Two-way binding for the open state. |
anchor | BuiPopoverAnchor | ElementRef | Element | { x: number; y: number } | null | null | An external anchor to position the popover against. When set, the overlay is positioned relative to this anchor instead of the trigger. Accepts a buiPopoverAnchor directive reference, an ElementRef, a native DOM element, or a fixed point ({ x, y }). |
position | PopoverPosition | 'bottom' | Preferred placement relative to the trigger. Automatically flips to a fallback position if there is not enough space. |
offset | number | 4 | Distance in pixels between the trigger and the popover panel. |
autoFocus | 'dialog' | 'first-tabbable' | 'first-heading' | string | undefined | 'first-tabbable' | Configures where focus goes when the dialog opens. |
closeOnScroll | boolean | false | When true, the popover automatically closes when the user scrolls any scrollable ancestor. |
restoreFocus | boolean | string | HTMLElement | true | Configures where focus returns when the dialog closes. |
(opened) | void | — | Emits when the popover opens. |
(closed) | void | — | Emits after the popover closes and its exit animation completes. |
The position input accepts one of 12 placement values:
top,top-start,top-endbottom,bottom-start,bottom-endstart,start-top,start-bottomend,end-top,end-bottom
Trigger
Apply buiPopoverTrigger to a button or any clickable element. It toggles the popover on click, automatically sets aria-expanded, aria-controls, and keyboard support (Enter / Space). The trigger element also serves as the default positioning anchor for the overlay unless an external anchor is provided.
<button matButton buiPopoverTrigger>Open Popover</button>Anchor
By default the popover is positioned relative to the trigger element. When you need the overlay to appear next to a different element, use the anchor input on buiPopover.
The simplest approach is the buiPopoverAnchor directive. Apply it to any element and pass the reference to the anchor input:
<span buiPopoverAnchor #myAnchor="buiPopoverAnchor">
Anchor element
</span>
<div buiPopover [anchor]="myAnchor">
<button matButton buiPopoverTrigger>Open</button>
<ng-template buiPopoverPortal>
<div buiPopoverContent>...</div>
</ng-template>
</div> You can also pass an ElementRef, a native DOM Element, or a fixed point ({ x: number; y: number }) for absolute positioning:
<!-- Fixed point -->
<div buiPopover [anchor]="{ x: 200, y: 400 }">
<button matButton buiPopoverTrigger>Open</button>
<ng-template buiPopoverPortal>
<div buiPopoverContent>...</div>
</ng-template>
</div><div buiPopover [anchor]="externalAnchor">
<button matButton buiPopoverTrigger>Open Popover</button>
<ng-template buiPopoverPortal>
<div buiPopoverContent>
<p buiPopoverDescription>
This popover is anchored to the pill
on the right, not the trigger button.
</p>
</div>
</ng-template>
</div>
<span
buiPopoverAnchor
#externalAnchor="buiPopoverAnchor"
class="rounded-full bg-neutral-a3 px-3 py-1 text-xs font-medium"
>
Anchor element
</span>Portal
The buiPopoverPortal directive goes on an ng-template. Its content is projected into a CDK overlay anchored to the trigger when the popover opens.
<ng-template buiPopoverPortal>
<div buiPopoverContent>
<!-- title, description, or any custom content -->
</div>
</ng-template>Content
The buiPopoverContent directive marks the floating panel. It handles entry/exit animations and provides the visual styling (border, shadow, background). Place title, description, or any custom content inside it.
<div buiPopoverContent>
<h3 buiPopoverTitle>Title</h3>
<p buiPopoverDescription>Description text</p>
</div>
<!-- Custom content -->
<div buiPopoverContent>
<p>Any content can go here.</p>
<button matButton buiPopoverClose>Close</button>
</div>Close
Apply buiPopoverClose to any element inside the portal. It closes the popover when clicked. Attach your own (click) handler separately for additional logic.
<button matButton buiPopoverClose (click)="onSave()">
Save & Close
</button>Title & Description
buiPopoverTitle and buiPopoverDescription are optional directives for structured content. The title connects to aria-labelledby and the description connects to aria-describedby on the popover container.
<div buiPopoverContent>
<h3 buiPopoverTitle>Dimensions</h3>
<p buiPopoverDescription>
Set the dimensions for the layer.
</p>
</div>Position
Use the position input to control where the popover appears relative to the trigger. The popover automatically flips to a fallback position if there is not enough space.
<!-- Bottom (default) -->
<div buiPopover position="bottom">...</div>
<!-- Top -->
<div buiPopover position="top">...</div>
<!-- Start (left in LTR) -->
<div buiPopover position="start">...</div>
<!-- End (right in LTR) -->
<div buiPopover position="end">...</div>
<!-- Aligned variants -->
<div buiPopover position="bottom-start">...</div>
<div buiPopover position="top-end">...</div>Programmatic control
You can control the popover without a trigger. Use the open model for two-way binding, or grab a template reference via #ref="buiPopover" and call open(), close(), or toggle().
<!-- Two-way binding -->
<div buiPopover [(open)]="isPopoverOpen">
<button matButton buiPopoverTrigger>Open</button>
<ng-template buiPopoverPortal>
<div buiPopoverContent>...</div>
</ng-template>
</div>
<!-- Template reference -->
<div buiPopover #myPopover="buiPopover">
<button matButton buiPopoverTrigger>Open</button>
<ng-template buiPopoverPortal>
<div buiPopoverContent>...</div>
</ng-template>
</div>
<button matButton (click)="myPopover.open()">Open</button>
<button matButton (click)="myPopover.close()">Close</button>
<button matButton (click)="myPopover.toggle()">Toggle</button>