Popover

Popover is a container component that can overlay other components on page.


import { PopoverModule } from 'primeng/popover';

Popover is accessed via its reference and visibility is controlled using toggle, show and hide methods with an event of the target.


<p-button (click)="op.toggle($event)" icon="pi pi-share-alt" label="Share" />
    <p-popover #op>
        <div class="flex flex-col gap-4 w-[25rem]">
            <div>
                <span class="font-medium text-surface-900 dark:text-surface-0 block mb-2">Share this document</span>
                <p-inputgroup>
                    <input pInputText value="https://primeng.org/12323ff26t2g243g423g234gg52hy25XADXAG3" readonly class="w-[25rem]" />
                    <p-inputgroup-addon>
                        <i class="pi pi-copy"></i>
                    </p-inputgroup-addon>
                </p-inputgroup>
            </div>
            <div>
                <span class="font-medium text-surface-900 dark:text-surface-0 block mb-2">Invite Member</span>
                <div class="flex">
                    <p-inputgroup>
                        <input pInputText disabled />
                        <button pButton label="Invite" icon="pi pi-users"></button>
                    </p-inputgroup>
                </div>
            </div>
            <div>
                <span class="font-medium text-surface-900 dark:text-surface-0 block mb-2">Team Members</span>
                <ul class="list-none p-0 m-0 flex flex-col gap-4">
                    <li *ngFor="let member of members" class="flex items-center gap-2">
                        <img [src]="'https://primefaces.org/cdn/primeng/images/demo/avatar/' + member.image" style="width: 32px" />
                        <div>
                            <span class="font-medium">{{ member.name }}</span>
                            <div class="text-sm text-muted-color">{{ member.email }}</div>
                        </div>
                        <div class="flex items-center gap-2 text-muted-color ml-auto text-sm">
                            <span>{{ member.role }}</span>
                            <i class="pi pi-angle-down"></i>
                        </div>
                    </li>
                </ul>
            </div>
        </div>
    </p-popover>

In this sample, data is retrieved from the content inside the popover.


<p-button
    type="button"
    [label]="selectedMember ? selectedMember.name : 'Select Member'"
    (onClick)="toggle($event)"
    styleClass="min-w-48"
/>

<p-popover #op>
    <div class="flex flex-col gap-4">
        <div>
            <span class="font-medium block mb-2">Team Members</span>
            <ul class="list-none p-0 m-0 flex flex-col">
                <li
                    *ngFor="let member of members"
                    class="flex items-center gap-2 px-2 py-3 hover:bg-emphasis cursor-pointer rounded-border"
                    (click)="selectMember(member)"
                >
                    <img [src]="'https://primefaces.org/cdn/primeng/images/demo/avatar/' + member.image" style="width: 32px" />
                    <div>
                        <span class="font-medium">{{ member.name }}</span>
                        <div class="text-sm text-surface-500 dark:text-surface-400">{{ member.email }}</div>
                    </div>
                </li>
            </ul>
        </div>
    </div>
</p-popover>

Place the Popover outside of the data iteration components to avoid rendering it multiple times.

IdCodeNamePrice ImageDetails
1000f230fh0g3Bamboo Watch$ 65bamboo-watch.jpg
1001nvklal433Black Watch$ 72black-watch.jpg
1002zz21cz3c1Blue Band$ 79blue-band.jpg
1003244wgerg2Blue T-Shirt$ 29blue-t-shirt.jpg
1004h456wer53Bracelet$ 15bracelet.jpg

<p-table [value]="products" [tableStyle]="{ 'min-width': '50rem' }" [paginator]="true" [rows]="5">
    <ng-template pTemplate="header">
        <tr>
            <th class="w-1/6">Id</th>
            <th class="w-1/6">Code</th>
            <th class="w-1/6">Name</th>
            <th class="w-1/6" pSortableColumn="price">Price <p-sortIcon field="price" /></th>
            <th class="w-1/6">Image</th>
            <th class="w-1/6">Details</th>
        </tr>
    </ng-template>
    <ng-template pTemplate="body" let-product>
        <tr>
            <td>{{ product.id }}</td>
            <td>{{ product.code }}</td>
            <td>{{ product.name }}</td>
            <td>$ {{ product.price }}</td>
            <td>
                <img
                    [src]="'https://primefaces.org/cdn/primeng/images/demo/product/' + product.image"
                    [alt]="product.image"
                    class="w-16 shadow-sm"
                />
            </td>
            <td>
                <p-button (onClick)="displayProduct($event, product)" icon="pi pi-search" severity="secondary" rounded />
            </td>
        </tr>
    </ng-template>
</p-table>
<p-popover #op (onHide)="selectedProduct = null">
    <ng-template pTemplate="content">
        <div *ngIf="selectedProduct" class="rounded flex flex-col">
            <div class="flex justify-center rounded">
                <div class="relative mx-auto">
                    <img
                        class="rounded w-44 sm:w-64"
                        [src]="'https://primefaces.org/cdn/primeng/images/demo/product/' + selectedProduct.image"
                        [alt]="selectedProduct.name"
                    />
                    <p-tag
                        [value]="selectedProduct.inventoryStatus"
                        [severity]="getSeverity(selectedProduct)"
                        class="absolute"
                        styleClass="dark:!bg-surface-900"
                        [style.left.px]="4"
                        [style.top.px]="4"
                    />
                </div>
            </div>
            <div class="pt-4">
                <div class="flex flex-row justify-between items-start gap-2 mb-4">
                    <div>
                        <span class="font-medium text-surface-500 dark:text-surface-400 text-sm">{{
                            selectedProduct.category
                        }}</span>
                        <div class="text-lg font-medium mt-1">{{ selectedProduct.name }}</div>
                    </div>
                    <div class="bg-surface-100 p-1" style="border-radius: 30px">
                        <div
                            class="bg-surface-0 flex items-center gap-2 justify-center py-1 px-2"
                            style="border-radius: 30px; box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.04), 0px 1px 2px 0px rgba(0, 0, 0, 0.06)"
                        >
                            <span class="text-surface-900 font-medium text-sm">{{ selectedProduct.rating }}</span>
                            <i class="pi pi-star-fill text-yellow-500"></i>
                        </div>
                    </div>
                </div>
                <div class="flex gap-2">
                    <p-button
                        icon="pi pi-shopping-cart"
                        [label]="'Buy Now | $' + selectedProduct.price"
                        [disabled]="selectedProduct.inventoryStatus === 'OUTOFSTOCK'"
                        class="flex-auto whitespace-nowrap"
                        (onClick)="hidePopover()"
                    />
                    <p-button icon="pi pi-heart" outlined (onClick)="hidePopover()" />
                </div>
            </div>
        </div>
    </ng-template>
</p-popover>

Screen Reader

Popover component uses dialog role and since any attribute is passed to the root element you may define attributes like aria-label or aria-labelledby to describe the popup contents. In addition aria-modal is added since focus is kept within the popup.

It is recommended to use a trigger component that can be accessed with keyboard such as a button, if not adding tabIndex would be necessary. Popover adds aria-expanded state attribute and aria-controls to the trigger so that the relation between the trigger and the popup is defined.

Popover Keyboard Support

When the popup gets opened, the first focusable element receives the focus and this can be customized by adding autofocus to an element within the popup.

KeyFunction
tabMoves focus to the next the focusable element within the popup.
shift + tabMoves focus to the previous the focusable element within the popup.
escapeCloses the popup and moves focus to the trigger.

Close Button Keyboard Support

KeyFunction
enterCloses the popup and moves focus to the trigger.
spaceCloses the popup and moves focus to the trigger.