skeleton

Use to show a placeholder while content is loading.

PreviousNext
import { ChangeDetectionStrategy, Component } from '@angular/core';

import { ZardSkeletonComponent } from '@/shared/components/skeleton/skeleton.component';

@Component({
  selector: 'z-demo-skeleton-preview',
  imports: [ZardSkeletonComponent],
  template: `
    <div class="flex items-center space-x-4">
      <z-skeleton class="size-12 rounded-full" />
      <div class="space-y-2">
        <z-skeleton class="h-4 w-[250px]" />
        <z-skeleton class="h-4 w-[200px]" />
      </div>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoSkeletonPreviewComponent {}

Installation

Copy
npx zard-cli@latest add skeleton

Usage

import { ZardSkeletonComponent } from '@/shared/components/skeleton/skeleton.component';
Copy
<z-skeleton class="h-4 w-[250px]"></z-skeleton>
Copy

Examples

avatar

A compact avatar label: a size-10 circle standing in for z-avatar next to two short bars for a name and a secondary line.
import { ChangeDetectionStrategy, Component } from '@angular/core';

import { ZardSkeletonComponent } from '@/shared/components/skeleton/skeleton.component';

@Component({
  selector: 'z-demo-skeleton-avatar',
  imports: [ZardSkeletonComponent],
  template: `
    <div class="flex w-fit items-center gap-4">
      <z-skeleton class="size-10 shrink-0 rounded-full" />
      <div class="grid gap-2">
        <z-skeleton class="h-4 w-[150px]" />
        <z-skeleton class="h-4 w-[100px]" />
      </div>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoSkeletonAvatarComponent {}

card

A loading z-card: the title and description bars are passed to z-card-title/z-card-description through their zTitle/zDescription template inputs, and an aspect-video bar fills z-card-content in place of media.
import { ChangeDetectionStrategy, Component } from '@angular/core';

import { ZardCardImports } from '@/shared/components/card/card.imports';
import { ZardSkeletonComponent } from '@/shared/components/skeleton/skeleton.component';

@Component({
  selector: 'z-demo-skeleton-card',
  imports: [ZardCardImports, ZardSkeletonComponent],
  template: `
    <z-card class="w-full min-w-xs">
      <z-card-header>
        <z-card-title [zTitle]="titleSkeleton" />
        <z-card-description [zDescription]="descriptionSkeleton" />
      </z-card-header>
      <z-card-content>
        <z-skeleton class="aspect-video w-full" />
      </z-card-content>
    </z-card>

    <ng-template #titleSkeleton>
      <z-skeleton class="h-4 w-2/3" />
    </ng-template>

    <ng-template #descriptionSkeleton>
      <z-skeleton class="h-4 w-1/2" />
    </ng-template>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoSkeletonCardComponent {}

text

A paragraph of body copy: three full-width lines, the last one narrower to mimic a line that does not reach the margin.
import { ChangeDetectionStrategy, Component } from '@angular/core';

import { ZardSkeletonComponent } from '@/shared/components/skeleton/skeleton.component';

@Component({
  selector: 'z-demo-skeleton-text',
  imports: [ZardSkeletonComponent],
  template: `
    <div class="flex w-full min-w-xs flex-col gap-2">
      <z-skeleton class="h-4 w-full" />
      <z-skeleton class="h-4 w-full" />
      <z-skeleton class="h-4 w-3/4" />
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoSkeletonTextComponent {}

form

Two label-and-control pairs plus a submit action: each label bar sits above an h-8 bar matching the height of z-input, and the trailing h-8 bar matches a default z-button.
import { ChangeDetectionStrategy, Component } from '@angular/core';

import { ZardSkeletonComponent } from '@/shared/components/skeleton/skeleton.component';

@Component({
  selector: 'z-demo-skeleton-form',
  imports: [ZardSkeletonComponent],
  template: `
    <div class="flex w-full min-w-xs flex-col gap-7">
      <div class="flex flex-col gap-3">
        <z-skeleton class="h-4 w-20" />
        <z-skeleton class="h-8 w-full" />
      </div>
      <div class="flex flex-col gap-3">
        <z-skeleton class="h-4 w-24" />
        <z-skeleton class="h-8 w-full" />
      </div>
      <z-skeleton class="h-8 w-24" />
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoSkeletonFormComponent {}

table

A z-table body: five rows, each with a flexible primary-column bar and two fixed-width bars for secondary columns.
import { ChangeDetectionStrategy, Component } from '@angular/core';

import { ZardSkeletonComponent } from '@/shared/components/skeleton/skeleton.component';

@Component({
  selector: 'z-demo-skeleton-table',
  imports: [ZardSkeletonComponent],
  template: `
    <div class="flex w-full min-w-sm flex-col gap-2">
      @for (row of rows; track row) {
        <div class="flex gap-4">
          <z-skeleton class="h-4 flex-1" />
          <z-skeleton class="h-4 w-24" />
          <z-skeleton class="h-4 w-20" />
        </div>
      }
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoSkeletonTableComponent {
  protected readonly rows = [0, 1, 2, 3, 4];
}

rtl

To enable RTL support in zard/ui, see the RTL configuration guide.
// You will notice this example is rendered inside a wrapper that sets the dir and data-lang attributes, and
// reads its text from a translations helper. This is because this site is not RTL by default.
// In your application you won't need either: set dir="rtl" on <html> (or use the CDK Dir directive on a subtree)
// and write the text of your own language. See the RTL guide: https://zardui.com/docs/rtl

import { ChangeDetectionStrategy, Component } from '@angular/core';

import { ZardSkeletonComponent } from '@/shared/components/skeleton/skeleton.component';
import { injectRtlTranslation, type ZardRtlTranslations } from '@/shared/demo-utils/rtl-translation';

const translations: ZardRtlTranslations<{ caption: string }> = {
  en: {
    dir: 'ltr',
    values: {
      caption: 'Loading profile',
    },
  },
  ar: {
    dir: 'rtl',
    values: {
      caption: 'جارٍ تحميل الملف الشخصي',
    },
  },
  he: {
    dir: 'rtl',
    values: {
      caption: 'טוען פרופיל',
    },
  },
};

@Component({
  selector: 'z-demo-skeleton-rtl',
  imports: [ZardSkeletonComponent],
  template: `
    <div class="flex w-fit items-center gap-4" role="status" [attr.aria-label]="i18n.t().caption">
      <z-skeleton class="size-10 shrink-0 rounded-full" />
      <div class="grid gap-2">
        <z-skeleton class="h-4 w-[150px]" />
        <z-skeleton class="h-4 w-[100px]" />
      </div>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoSkeletonRtlComponent {
  protected readonly i18n = injectRtlTranslation(translations);
}

API Reference

z-skeletonComponent

Renders a customizable placeholder during data loading to improve perceived performance and prevent layout shifts. `class` is the only input — size and shape the placeholder yourself with utility classes (`size-12 rounded-full`, `h-4 w-full`, ...) to match the content it stands in for.

PropertyDescriptionTypeDefault
[class] Custom CSS classes sizing and shaping the placeholder string ''
github iconwhatsapp icondiscord iconX icon

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