dialog

Visually or semantically separates content.

PreviousNext
import { ChangeDetectionStrategy, Component, inject, type AfterViewInit } from '@angular/core';
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';

import { ZardDialogImports } from '@/shared/components/dialog/dialog.imports';

import { ZardInputComponent } from '../../input/input.component';
import { Z_MODAL_DATA, ZardDialogService } from '../dialog.service';

interface iDialogData {
  name: string;
  username: string;
}

@Component({
  selector: 'z-demo-dialog-basic',
  imports: [FormsModule, ReactiveFormsModule, ZardInputComponent],
  template: `
    <form [formGroup]="form" class="grid gap-4">
      <div class="grid gap-3">
        <label for="name" class="text-sm leading-none font-medium select-none">Name</label>
        <input z-input id="name" formControlName="name" />
      </div>

      <div class="grid gap-3">
        <label for="username" class="text-sm leading-none font-medium select-none">Username</label>
        <input z-input id="username" formControlName="username" />
      </div>
    </form>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  exportAs: 'zardDemoDialogBasic',
})
export class ZardDemoDialogBasicInputComponent implements AfterViewInit {
  private zData = inject(Z_MODAL_DATA) as iDialogData;

  form = new FormGroup({
    name: new FormControl('Pedro Duarte'),
    username: new FormControl('@peduarte'),
  });

  ngAfterViewInit(): void {
    if (this.zData) {
      this.form.patchValue(this.zData);
    }
  }
}

@Component({
  imports: [ZardDialogImports],
  template: `
    <button type="button" z-button zType="outline" (click)="openDialog()">Edit profile</button>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoDialogBasicComponent {
  private dialogService = inject(ZardDialogService);

  openDialog() {
    this.dialogService.create({
      zTitle: 'Edit Profile',
      zDescription: `Make changes to your profile here. Click save when you're done.`,
      zContent: ZardDemoDialogBasicInputComponent,
      zData: {
        name: 'Samuel Rizzon',
        username: '@samuelrizzondev',
      } as iDialogData,
      zOkText: 'Save changes',
      zOnOk: instance => {
        console.log('Form submitted:', instance.form.value);
      },
    });
  }
}

Installation

Copy
npx zard-cli@latest add dialog

Usage

import { ZardDialogImports } from '@/shared/components/dialog/dialog.imports';
Copy
<z-dialog zTitle="Edit profile" zDescription="Make changes to your profile here.">
  <p>Dialog content goes here.</p>
</z-dialog>
Copy

Examples

custom close

Replace the default close control with your own button.
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';

import { ZardButtonComponent } from '@/shared/components/button/button.component';
import { ZardDialogRef } from '@/shared/components/dialog/dialog-ref';
import { ZardDialogService } from '@/shared/components/dialog/dialog.service';
import { ZardInputComponent } from '@/shared/components/input/input.component';

@Component({
  selector: 'z-demo-dialog-custom-close-content',
  imports: [ZardButtonComponent, ZardInputComponent],
  template: `
    <div class="flex items-center gap-2">
      <div class="grid flex-1 gap-2">
        <label for="link" class="sr-only">Link</label>
        <input z-input id="link" value="https://ui.zardui.com/docs/installation" readonly />
      </div>
    </div>
    <footer
      class="bg-muted/50 -mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t p-4 sm:flex-row sm:justify-start"
    >
      <button type="button" z-button (click)="dialogRef.close()">Close</button>
    </footer>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoDialogCustomCloseContentComponent {
  protected readonly dialogRef = inject(ZardDialogRef);
}

@Component({
  selector: 'z-demo-dialog-custom-close',
  imports: [ZardButtonComponent],
  template: `
    <button type="button" z-button zType="outline" (click)="open()">Share</button>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoDialogCustomCloseComponent {
  private readonly dialogService = inject(ZardDialogService);

  open() {
    this.dialogService.create({
      zTitle: 'Share link',
      zDescription: 'Anyone who has this link will be able to view this.',
      zContent: ZardDemoDialogCustomCloseContentComponent,
      zHideFooter: true,
    });
  }
}

no close button

Use zClosable: false to hide the close button.
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';

import { ZardButtonComponent } from '@/shared/components/button/button.component';
import { ZardDialogService } from '@/shared/components/dialog/dialog.service';

@Component({
  selector: 'z-demo-dialog-no-close-button',
  imports: [ZardButtonComponent],
  template: `
    <button type="button" z-button zType="outline" (click)="open()">No Close Button</button>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoDialogNoCloseButtonComponent {
  private readonly dialogService = inject(ZardDialogService);

  open() {
    this.dialogService.create({
      zTitle: 'No Close Button',
      zDescription: "This dialog doesn't have a close button in the top-right corner.",
      zClosable: false,
      zHideFooter: true,
    });
  }
}

sticky footer

Keep actions visible while the content scrolls.
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';

import { ZardButtonComponent } from '@/shared/components/button/button.component';
import { ZardDialogService } from '@/shared/components/dialog/dialog.service';

const PARAGRAPHS = Array.from({ length: 10 }).map(
  () =>
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
);

@Component({
  selector: 'z-demo-dialog-sticky-footer-content',
  template: `
    <div class="no-scrollbar -mx-4 max-h-[50vh] overflow-y-auto px-4">
      @for (paragraph of paragraphs; track $index) {
        <p class="mb-4 leading-normal">{{ paragraph }}</p>
      }
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoDialogStickyFooterContentComponent {
  protected readonly paragraphs = PARAGRAPHS;
}

@Component({
  selector: 'z-demo-dialog-sticky-footer',
  imports: [ZardButtonComponent],
  template: `
    <button type="button" z-button zType="outline" (click)="open()">Sticky Footer</button>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoDialogStickyFooterComponent {
  private readonly dialogService = inject(ZardDialogService);

  open() {
    this.dialogService.create({
      zTitle: 'Sticky Footer',
      zDescription: 'This dialog has a sticky footer that stays visible while the content scrolls.',
      zContent: ZardDemoDialogStickyFooterContentComponent,
      zCancelText: 'Close',
      zOkText: null,
    });
  }
}

scrollable content

Long content can scroll while the header stays in view.
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';

import { ZardButtonComponent } from '@/shared/components/button/button.component';
import { ZardDialogService } from '@/shared/components/dialog/dialog.service';

const PARAGRAPHS = Array.from({ length: 10 }).map(
  () =>
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
);

@Component({
  selector: 'z-demo-dialog-scrollable-content-content',
  template: `
    <div class="no-scrollbar -mx-4 max-h-[50vh] overflow-y-auto px-4">
      @for (paragraph of paragraphs; track $index) {
        <p class="mb-4 leading-normal">{{ paragraph }}</p>
      }
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoDialogScrollableContentInnerComponent {
  protected readonly paragraphs = PARAGRAPHS;
}

@Component({
  selector: 'z-demo-dialog-scrollable-content',
  imports: [ZardButtonComponent],
  template: `
    <button type="button" z-button zType="outline" (click)="open()">Scrollable Content</button>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoDialogScrollableContentComponent {
  private readonly dialogService = inject(ZardDialogService);

  open() {
    this.dialogService.create({
      zTitle: 'Scrollable Content',
      zDescription: 'This is a dialog with scrollable content.',
      zContent: ZardDemoDialogScrollableContentInnerComponent,
      zHideFooter: true,
    });
  }
}

API Reference

ZardDialogServiceComponent

Provides methods to open and close dialogs.

PropertyDescriptionTypeDefault
[zAutofocus] Sets the autofocus button. 'ok' | 'cancel' | 'auto' | null 'auto'
[zCancelIcon] Sets the cancel icon. string
[zCancelText] Sets the cancel text. string
[zClosable] Enables closing the dialog. boolean true
[zContent] Sets the dialog content. string | TemplateRef<T> | Type<T>
[zData] Sets the data for the dialog. U
[zDescription] Sets the dialog description. string
[zHideFooter] Hides the footer. boolean false
[zHideHeader] Keeps the title and description available to screen readers only (`sr-only`). boolean false
[zMaskClosable] Enables closing the dialog by clicking on the mask. boolean true
[zOkDestructive] Marks the OK button as destructive. boolean false
[zOkDisabled] Disables the OK button. boolean false
[zOkIcon] Sets the OK button icon. string
[zOkText] Sets the OK button text. string | null
[zOnCancel] Callback for cancel action. EventEmitter<T> | OnClickCallback<T> noopFn
[zOnOk] Callback for OK action. EventEmitter<T> | OnClickCallback<T> noopFn
[zTitle] Sets the dialog title. string | TemplateRef<T>
[zViewContainerRef] View container reference for dynamic component loading. ViewContainerRef
[zWidth] Sets the dialog width. string
github iconwhatsapp icondiscord iconX icon

Made with in Brazil. Open source and available on GitHub .