Dialog

Dialog is a container to display content in an overlay window.


import { DialogModule } from 'primeng/dialog';

Dialog is used as a container and visibility is controlled with visible property.


<p-button (click)="showDialog()" label="Show" />
<p-dialog header="Edit Profile" [modal]="true" [(visible)]="visible" [style]="{ width: '25rem' }">
    <span class="p-text-secondary block mb-8">Update your information.</span>
    <div class="flex items-center gap-4 mb-4">
        <label for="username" class="font-semibold w-24">Username</label>
        <input pInputText id="username" class="flex-auto" autocomplete="off" />
    </div>
    <div class="flex items-center gap-4 mb-8">
        <label for="email" class="font-semibold w-24">Email</label>
        <input pInputText id="email" class="flex-auto" autocomplete="off" />
    </div>
    <div class="flex justify-end gap-2">
        <p-button label="Cancel" severity="secondary" (click)="visible = false" />
        <p-button label="Save" (click)="visible = false" />
    </div>
</p-dialog>

Dialog can be customized using header and footer templates.


<p-button (click)="showDialog()" label="Show" />
<p-dialog 
    header="Header" 
    [(visible)]="visible" 
    [modal]="true" 
    [style]="{ width: '25rem' }">
        <ng-template pTemplate="header">
            <div class="inline-flex items-center justify-center gap-2">
                <p-avatar 
                    image="https://primefaces.org/cdn/primeng/images/demo/avatar/amyelsner.png" 
                    shape="circle" />
                <span class="font-bold whitespace-nowrap">
                    Amy Elsner
                </span>
            </div>
        </ng-template>
        <span class="p-text-secondary block mb-8">Update your information.</span>
        <div class="flex items-center gap-4 mb-4">
            <label for="username" class="font-semibold w-24">
                Username
            </label>
            <input pInputText id="username" class="flex-auto" autocomplete="off" />
        </div>
        <div class="flex items-center gap-4 mb-8">
            <label for="email" class="font-semibold w-24">Email</label>
            <input pInputText id="email" class="flex-auto" autocomplete="off" />
        </div>
        <ng-template pTemplate="footer">
            <p-button 
                label="Cancel" 
                [text]="true" 
                severity="secondary" 
                (click)="visible = false" />
            <p-button 
                label="Save" 
                [outlined]="true" 
                severity="secondary" 
                (click)="visible = false" 
              />
        </ng-template>
</p-dialog>

The position property is used to display a Dialog at all edges and corners of the screen.


<div class="flex flex-wrap justify-center gap-2 mb-2">
    <p-button (click)="showDialog('left')" icon="pi pi-arrow-right" label="Left" severity="secondary" styleClass="min-w-40" />
    <p-button (click)="showDialog('right')" icon="pi pi-arrow-left" label="Right" severity="secondary" styleClass="min-w-40" />
</div>
<div class="flex flex-wrap justify-center gap-2 mb-2">
    <p-button (click)="showDialog('topleft')" icon="pi pi-arrow-down-right" label="TopLeft" severity="secondary" styleClass="min-w-40" />
    <p-button (click)="showDialog('top')" icon="pi pi-arrow-down" label="Top" severity="secondary" styleClass="min-w-40" />
    <p-button (click)="showDialog('topright')" icon="pi pi-arrow-down-left" label="TopRight" severity="secondary" styleClass="min-w-40" />
</div>
<div class="flex flex-wrap justify-center gap-2">
    <p-button (click)="showDialog('bottomleft')" icon="pi pi-arrow-up-right" label="BottomLeft" severity="secondary" styleClass="min-w-40" />
    <p-button (click)="showDialog('bottom')" icon="pi pi-arrow-up" label="Bottom" severity="secondary" styleClass="min-w-40" />
    <p-button (click)="showDialog('bottomright')" icon="pi pi-arrow-up-left" label="BottomRight" severity="secondary" styleClass="min-w-40" />
</div>
<p-dialog header="Edit Profile" [modal]="true" [(visible)]="visible" [position]="position" [style]="{ width: '25rem' }">
    <span class="text-surface-500 dark:text-surface-400 block mb-8">Update your information.</span>
    <div class="flex items-center gap-4 mb-4">
        <label for="username" class="font-semibold w-24">Username</label>
        <input pInputText id="username" class="flex-auto" autocomplete="off" />
    </div>
    <div class="flex items-center gap-4 mb-8">
        <label for="email" class="font-semibold w-24">Email</label>
        <input pInputText id="email" class="flex-auto" autocomplete="off" />
    </div>
    <div class="flex justify-end gap-2">
        <p-button label="Cancel" severity="secondary" (click)="visible = false" />
        <p-button label="Save" (click)="visible = false" />
    </div>
</p-dialog>

Setting maximizable property to true enables the full screen mode.


<p-button (click)="showDialog()" label="Show" />
<p-dialog 
    header="Header" 
    [modal]="true"
    [(visible)]="visible" 
    [style]="{ width: '50rem' }" 
    [breakpoints]="{ '1199px': '75vw', '575px': '90vw' }" 
    [maximizable]="true">
        <p>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit...
        </p>
</p-dialog>

Dialog automatically displays a scroller when content exceeeds viewport.


<p-button (click)="showDialog()" label="Show" />
<p-dialog 
    header="Header" 
    [modal]="true"
    [(visible)]="visible" 
    [style]="{ width: '50rem' }" 
    [breakpoints]="{ '1199px': '75vw', '575px': '90vw' }">
        <p class="mb-8">
            Lorem ipsum dolor sit amet...
        </p>
        <p class="mb-8">
            "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium...
        </p>
        <p class="mb-8">
            At vero eos et accusamus et iusto odio dignissimos...
        </p>
        <p class="mb-8">
            Lorem ipsum dolor sit amet, consectetur adipiscing elit...
        </p>
        <p class="mb-8">
            "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium...
        </p>
        <p>
            At vero eos et accusamus et iusto odio dignissimos...
        </p>
</p-dialog>

Mask layer behind the Dialog is configured with the modal property. By default, no modal layer is added.


<p-button (click)="showDialog()" label="Show" />
<p-dialog header="Edit Profile" [(visible)]="visible" [style]="{ width: '25rem' }">
    <span class="p-text-secondary block mb-8">Update your information.</span>
    <div class="flex items-center gap-4 mb-4">
        <label for="username" class="font-semibold w-24">Username</label>
        <input pInputText id="username" class="flex-auto" autocomplete="off" />
    </div>
    <div class="flex items-center gap-4 mb-8">
        <label for="email" class="font-semibold w-24">Email</label>
        <input pInputText id="email" class="flex-auto" autocomplete="off" />
    </div>
    <div class="flex justify-end gap-2">
        <p-button label="Cancel" severity="secondary" (click)="visible = false" />
        <p-button label="Save" (click)="visible = false" />
    </div>
</p-dialog>

Dialog width can be adjusted per screen size with the breakpoints option where a key defines the max-width for the breakpoint and value for the corresponding width. When no breakpoint matches width defined in style property is used.


<p-button (click)="showDialog()" label="Show" />
<p-dialog 
    header="Header" 
    [(visible)]="visible" 
    [modal]="true" 
    [breakpoints]="{ '1199px': '75vw', '575px': '90vw' }" 
    [style]="{ width: '50vw' }" 
    [draggable]="false" 
    [resizable]="false">
        <p>
            Lorem ipsum dolor sit amet...
        </p>
</p-dialog>

Headless mode allows you to customize the entire user interface instead of the default elements.


<p-button (click)="showDialog()" icon="pi pi-user" label="Login" />
<p-dialog maskStyleClass="backdrop-blur-sm" [(visible)]="visible" styleClass="!border-0 !bg-transparent">
    <ng-template pTemplate="headless">
        <div
            class="flex flex-col px-8 py-8 gap-6 rounded-2xl"
            style="border-radius: 12px; background-image: radial-gradient(circle at left top, var(--p-primary-400), var(--p-primary-700))"
        >
            <svg
                width="31"
                height="33"
                viewBox="0 0 31 33"
                fill="none"
                xmlns="http://www.w3.org/2000/svg"
                class="block mx-auto"
            >
                <path
                    d="..."
                    fill="var(--p-primary-color)"
                />
                <mask
                    id="mask0_1_52"
                    style="mask-type:luminance"
                    maskUnits="userSpaceOnUse"
                    x="0"
                    y="0"
                    width="31"
                    height="33"
                >
                    <path
                        d="..."
                        fill="var(--high-contrast-text-color)"
                    />
                </mask>
                <g mask="url(#mask0_1_52)">
                    <path
                        fill-rule="evenodd"
                        clip-rule="evenodd"
                        d="..."
                        fill="var(--p-primary-color)"
                    />
                </g>
                <path
                    d="..."
                    fill="var(--high-contrast-text-color)"
                />
                <path
                    d="..."
                    fill="var(--high-contrast-text-color)"
                />
                <path
                    fill-rule="evenodd"
                    clip-rule="evenodd"
                    d="..."
                    fill="var(--high-contrast-text-color)"
                />
                <path
                    d="..."
                    fill="var(--high-contrast-text-color)"
                />
                <path
                    d="..."
                    fill="var(--high-contrast-text-color)"
                />
                <path
                    fill-rule="evenodd"
                    clip-rule="evenodd"
                    d="..."
                    fill="var(--high-contrast-text-color)"
                />
                <path
                    d="..."
                    fill="var(--high-contrast-text-color)"
                />
                <path
                    d="..."
                    fill="var(--high-contrast-text-color)"
                />
                <path
                    d="..."
                    fill="var(--high-contrast-text-color)"
                />
                <path
                    d="..."
                    fill="var(--high-contrast-text-color)"
                />
            </svg>
            <div class="inline-flex flex-col gap-2">
                <label for="username" class="text-primary-50 font-semibold">Username</label>
                <input pInputText id="username" class="!bg-white/20 !border-0 !p-4 !text-primary-50 w-80" />
            </div>
            <div class="inline-flex flex-col gap-2">
                <label for="password" class="text-primary-50 font-semibold">Password</label>
                <input
                    pInputText
                    id="password"
                    class="!bg-white/20 !border-0 !p-4 !text-primary-50 w-80"
                    type="password"
                />
            </div>
            <div class="flex items-center gap-4">
                <p-button
                    label="Cancel"
                    (click)="closeDialog()"
                    [text]="true"
                    styleClass="!p-4 w-full !text-primary-50 !border !border-white/30 hover:!bg-white/10"
                    class="w-full"
                />
                <p-button
                    label="Sign-In"
                    (click)="closeDialog()"
                    [text]="true"
                    styleClass="!p-4 w-full !text-primary-50 !border !border-white/30 hover:!bg-white/10"
                    class="w-full"
                />
            </div>
        </div>
    </ng-template>
</p-dialog>

Screen Reader

Dialog component uses dialog role along with aria-labelledby referring to the header element however any attribute is passed to the root element so you may use aria-labelledby to override this default behavior. 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.

Trigger element also requires aria-expanded and aria-controls to be handled explicitly.

Close element is a button with an aria-label that refers to the aria.close property of the locale API by default, you may usecloseButtonProps to customize the element and override the default aria-label.


<p-button icon="pi pi-external-link" (click)="visible = true" aria-controls="{{visible ? 'dialog' : null}}" aria-expanded="{{visible ? true : false}}" />
    
<p-dialog id="dialog" header="Header" [(visible)]="visible" [style]="{ width: '50vw' }" (onHide)="visible = false">
    <p>Content</p>
</p-dialog>

Overlay Keyboard Support

KeyFunction
tabMoves focus to the next the focusable element within the dialog.
shift + tabMoves focus to the previous the focusable element within the dialog.
escapeCloses the dialog if closeOnEscape is true.

Close Button Keyboard Support

KeyFunction
enterCloses the dialog.
spaceCloses the dialog.