Empty

The Empty component displays a placeholder when no data is available, commonly used in tables, lists, or search results.

PreviousNext
No Projects Yet
You haven't created any projects yet. Get started by creating your first project.
import { ChangeDetectionStrategy, Component } from '@angular/core';
 
import { ZardButtonComponent } from '../../button/button.component';
import { ZardIconComponent } from '../../icon/icon.component';
import { ZardEmptyComponent } from '../empty.component';
 
@Component({
  selector: 'z-demo-empty-default',
  imports: [ZardButtonComponent, ZardEmptyComponent, ZardIconComponent],
  standalone: true,
  template: `
    <z-empty
      zIcon="folder-code"
      zTitle="No Projects Yet"
      zDescription="You haven't created any projects yet. Get started by creating your first project."
      [zActions]="[actionPrimary, actionSecondary]"
    >
      <ng-template #actionPrimary>
        <button z-button>Create Project</button>
      </ng-template>
 
      <ng-template #actionSecondary>
        <button z-button zType="outline">Import Project</button>
      </ng-template>
 
      <button z-button zType="link" zSize="sm" class="text-muted-foreground">
        Learn More
        <i z-icon zType="arrow-up-right"></i>
      </button>
    </z-empty>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoEmptyDefaultComponent {}
 

Installation

1

Run the CLI

Use the CLI to add the component to your project.

npx @ngzard/ui@latest add empty
1

Add the component files

Create the component directory structure and add the following files to your project.

empty.component.ts
empty.component.ts
import {
  ChangeDetectionStrategy,
  Component,
  computed,
  input,
  type TemplateRef,
  ViewEncapsulation,
} from '@angular/core';
 
import type { ClassValue } from 'clsx';
 
import {
  emptyActionsVariants,
  emptyDescriptionVariants,
  emptyHeaderVariants,
  emptyIconVariants,
  emptyImageVariants,
  emptyTitleVariants,
  emptyVariants,
} from './empty.variants';
import { mergeClasses } from '../../shared/utils/utils';
import { ZardStringTemplateOutletDirective } from '../core/directives/string-template-outlet/string-template-outlet.directive';
import { ZardIconComponent } from '../icon/icon.component';
import { type ZardIcon } from '../icon/icons';
 
@Component({
  selector: 'z-empty',
  imports: [ZardIconComponent, ZardStringTemplateOutletDirective],
  standalone: true,
  template: `
    @let image = zImage();
    @let icon = zIcon();
    @let title = zTitle();
    @let description = zDescription();
    @let actions = zActions();
 
    <div [class]="headerClasses()">
      @if (image) {
        <div [class]="imageClasses()">
          <ng-container *zStringTemplateOutlet="image">
            <img [src]="image" alt="Empty" class="mx-auto" />
          </ng-container>
        </div>
      } @else if (icon) {
        <div [class]="iconClasses()" data-testid="icon">
          <z-icon [zType]="icon" zSize="xl" />
        </div>
      }
 
      @if (title) {
        <div [class]="titleClasses()">
          <ng-container *zStringTemplateOutlet="title">{{ title }}</ng-container>
        </div>
      }
 
      @if (description) {
        <div [class]="descriptionClasses()">
          <ng-container *zStringTemplateOutlet="description">{{ description }}</ng-container>
        </div>
      }
    </div>
 
    @if (actions.length) {
      <div [class]="actionsClasses()">
        @for (action of actions; track $index) {
          <ng-container *zStringTemplateOutlet="action" />
        }
      </div>
    }
 
    <ng-content />
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  host: {
    '[class]': 'classes()',
  },
  exportAs: 'zEmpty',
})
export class ZardEmptyComponent {
  readonly zActions = input<TemplateRef<void>[]>([]);
  readonly zIcon = input<ZardIcon>();
  readonly zImage = input<string | TemplateRef<void>>();
  readonly zTitle = input<string | TemplateRef<void>>();
  readonly zDescription = input<string | TemplateRef<void>>();
  readonly class = input<ClassValue>('');
 
  protected readonly classes = computed(() => mergeClasses(emptyVariants(), this.class()));
  protected readonly headerClasses = computed(() => emptyHeaderVariants());
  protected readonly imageClasses = computed(() => emptyImageVariants());
  protected readonly iconClasses = computed(() => emptyIconVariants());
  protected readonly titleClasses = computed(() => emptyTitleVariants());
  protected readonly descriptionClasses = computed(() => emptyDescriptionVariants());
  protected readonly actionsClasses = computed(() => emptyActionsVariants());
}
 
empty.variants.ts
empty.variants.ts
import { cva } from 'class-variance-authority';
 
export const emptyVariants = cva(
  'flex min-w-0 flex-1 flex-col items-center justify-center gap-6 rounded-lg border-dashed p-6 text-center text-balance md:p-12',
  {
    variants: {},
  },
);
 
export const emptyHeaderVariants = cva('flex max-w-sm flex-col items-center gap-2 text-center', {
  variants: {},
});
 
export const emptyImageVariants = cva(
  'mb-2 flex shrink-0 items-center justify-center bg-transparent [&_svg]:pointer-events-none [&_svg]:shrink-0',
  {
    variants: {},
  },
);
 
export const emptyIconVariants = cva(
  `bg-muted text-foreground mb-2 flex size-10 shrink-0 items-center justify-center rounded-lg [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-6`,
  {
    variants: {},
  },
);
 
export const emptyTitleVariants = cva('text-lg font-medium tracking-tight', {
  variants: {},
});
 
export const emptyDescriptionVariants = cva(
  'text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4',
  {
    variants: {},
  },
);
 
export const emptyActionsVariants = cva(
  'flex w-full max-w-sm min-w-0 items-center justify-center gap-2 text-sm text-balance',
  {
    variants: {},
  },
);
 

Examples

default

No Projects Yet
You haven't created any projects yet. Get started by creating your first project.
import { ChangeDetectionStrategy, Component } from '@angular/core';
 
import { ZardButtonComponent } from '../../button/button.component';
import { ZardIconComponent } from '../../icon/icon.component';
import { ZardEmptyComponent } from '../empty.component';
 
@Component({
  selector: 'z-demo-empty-default',
  imports: [ZardButtonComponent, ZardEmptyComponent, ZardIconComponent],
  standalone: true,
  template: `
    <z-empty
      zIcon="folder-code"
      zTitle="No Projects Yet"
      zDescription="You haven't created any projects yet. Get started by creating your first project."
      [zActions]="[actionPrimary, actionSecondary]"
    >
      <ng-template #actionPrimary>
        <button z-button>Create Project</button>
      </ng-template>
 
      <ng-template #actionSecondary>
        <button z-button zType="outline">Import Project</button>
      </ng-template>
 
      <button z-button zType="link" zSize="sm" class="text-muted-foreground">
        Learn More
        <i z-icon zType="arrow-up-right"></i>
      </button>
    </z-empty>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoEmptyDefaultComponent {}
 

custom image

Empty
User Offline
This user is currently offline. You can leave a message to notify them or try again later.
import { ChangeDetectionStrategy, Component } from '@angular/core';
 
import { ZardButtonComponent } from '../../button/button.component';
import { ZardEmptyComponent } from '../empty.component';
 
@Component({
  selector: 'z-demo-empty-custom-image',
  imports: [ZardButtonComponent, ZardEmptyComponent],
  standalone: true,
  template: `
    <z-empty
      zImage="images/avatar/imgs/avatar_image.jpg"
      zTitle="User Offline"
      zDescription="This user is currently offline. You can leave a message to notify them or try again later."
      [zActions]="[actionPrimary]"
      class="[&_img]:size-12 [&_img]:rounded-full [&_img]:grayscale"
    />
 
    <ng-template #actionPrimary>
      <button z-button>Leave Message</button>
    </ng-template>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoEmptyCustomImageComponent {}
 

advanced

No Team members
Invite your team to collaborate on this project.
import { ChangeDetectionStrategy, Component } from '@angular/core';
 
import { ZardAvatarGroupComponent } from '../../avatar/avatar-group.component';
import { ZardAvatarComponent } from '../../avatar/avatar.component';
import { ZardButtonComponent } from '../../button/button.component';
import { ZardIconComponent } from '../../icon/icon.component';
import { ZardEmptyComponent } from '../empty.component';
 
@Component({
  selector: 'z-demo-empty-advanced-customization',
  imports: [ZardAvatarComponent, ZardAvatarGroupComponent, ZardButtonComponent, ZardIconComponent, ZardEmptyComponent],
  standalone: true,
  template: `
    <z-empty
      [zImage]="customImage"
      [zTitle]="customTitle"
      zDescription="Invite your team to collaborate on this project."
      [zActions]="[actionInvite]"
    />
 
    <ng-template #customImage>
      <z-avatar-group>
        <z-avatar zSrc="https://github.com/srizzon.png" zSize="md" class="grayscale" />
        <z-avatar zSrc="https://github.com/Luizgomess.png" zSize="md" class="grayscale" />
        <z-avatar zSrc="https://github.com/ribeiromatheuss.png" zSize="md" class="grayscale" />
        <z-avatar zSrc="https://github.com/mikij.png" zSize="md" class="grayscale" />
      </z-avatar-group>
    </ng-template>
 
    <ng-template #customTitle>
      <span>No Team <strong>members</strong></span>
    </ng-template>
 
    <ng-template #actionInvite>
      <button z-button zSize="sm">
        <i z-icon zType="plus"></i>
        Invite Members
      </button>
    </ng-template>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoEmptyAdvancedComponent {}
 

API

[z-empty] Component

z-empty component displays a placeholder when no data is available, commonly used in tables, lists, or search results.

To customize the empty, pass the following props to the component.

Property Description Type Default
zIcon Icon to display ZardIcon -
zImage Image URL or custom template string | TemplateRef<void> -
zDescription Description text or custom template string | TemplateRef<void> -
zTitle Title text or custom template string | TemplateRef<void> -
zActions Array of action templates TemplateRef<void>[] []
class Custom CSS classes ClassValue ''