Avatar

An image element with a fallback for representing the user.

PreviousNext
ZAZAJDSALU
import { Component } from '@angular/core';
 
import { ZardAvatarGroupComponent } from '../avatar-group.component';
import { ZardAvatarComponent } from '../avatar.component';
 
@Component({
  selector: 'z-demo-avatar-basic',
  imports: [ZardAvatarComponent, ZardAvatarGroupComponent],
  standalone: true,
  template: `
    <z-avatar zSrc="/images/avatar/imgs/avatar_image.jpg" zFallback="ZA" [zSize]="32" />
    <z-avatar zSrc="error-image.png" zFallback="ZA" zSize="sm" />
 
    <z-avatar-group>
      <z-avatar zSrc="/images/avatar/imgs/avatar_image.jpg" zFallback="JD" zSize="sm" />
      <z-avatar zSrc="https://github.com/srizzon.png" zFallback="SA" zSize="sm" />
      <z-avatar zSrc="https://github.com/Luizgomess.png" zFallback="LU" zSize="sm" />
    </z-avatar-group>
  `,
})
export class ZardDemoAvatarBasicComponent {}
 

Installation

1

Run the CLI

Use the CLI to add the component to your project.

npx @ngzard/ui@latest add avatar
1

Add the component files

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

avatar.component.ts
avatar.component.ts
import { ChangeDetectionStrategy, Component, computed, input, signal, ViewEncapsulation } from '@angular/core';
 
import { avatarVariants, imageVariants, type ZardImageVariants, type ZardAvatarVariants } from './avatar.variants';
import { mergeClasses } from '../../shared/utils/utils';
 
export type ZardAvatarStatus = 'online' | 'offline' | 'doNotDisturb' | 'away';
 
@Component({
  selector: 'z-avatar, [z-avatar]',
  standalone: true,
  template: `
    @if (zFallback() && (!zSrc() || !imageLoaded())) {
      <span class="absolute z-0 m-auto text-base">{{ zFallback() }}</span>
    }
 
    @if (zSrc() && !imageError()) {
      <img
        [src]="zSrc()"
        [alt]="zAlt()"
        [class]="imgClasses()"
        [hidden]="!imageLoaded()"
        (load)="onImageLoad()"
        (error)="onImageError()"
      />
    }
 
    @if (zStatus()) {
      @switch (zStatus()) {
        @case ('online') {
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="24"
            height="24"
            viewBox="0 0 24 24"
            fill="currentColor"
            stroke="white"
            stroke-width="2"
            stroke-linecap="round"
            stroke-linejoin="round"
            class="absolute -right-[5px] -bottom-[5px] z-20 h-5 w-5 text-green-500"
          >
            <circle cx="12" cy="12" r="10" fill="currentColor" />
          </svg>
        }
        @case ('offline') {
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="24"
            height="24"
            viewBox="0 0 24 24"
            fill="currentColor"
            stroke="white"
            stroke-width="2"
            stroke-linecap="round"
            stroke-linejoin="round"
            class="absolute -right-[5px] -bottom-[5px] z-20 h-5 w-5 text-red-500"
          >
            <circle cx="12" cy="12" r="10" fill="currentColor" />
          </svg>
        }
        @case ('doNotDisturb') {
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="24"
            height="24"
            viewBox="0 0 24 24"
            fill="currentColor"
            stroke="white"
            stroke-width="2"
            stroke-linecap="round"
            stroke-linejoin="round"
            class="absolute -right-[5px] -bottom-[5px] z-20 h-5 w-5 text-red-500"
          >
            <circle cx="12" cy="12" r="10" />
            <path d="M8 12h8" fill="currentColor" />
          </svg>
        }
        @case ('away') {
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="24"
            height="24"
            viewBox="0 0 24 24"
            fill="currentColor"
            stroke="white"
            stroke-width="2"
            stroke-linecap="round"
            stroke-linejoin="round"
            class="absolute -right-[5px] -bottom-[5px] z-20 h-5 w-5 rotate-y-180 text-yellow-400"
          >
            <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" fill="currentColor" />
          </svg>
        }
      }
    }
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  host: {
    '[class]': 'containerClasses()',
    '[style.width]': 'customSize()',
    '[style.height]': 'customSize()',
    '[attr.data-slot]': '"avatar"',
    '[attr.data-status]': 'zStatus() ?? null',
  },
  exportAs: 'zAvatar',
})
export class ZardAvatarComponent {
  readonly zStatus = input<ZardAvatarStatus>();
  readonly zShape = input<ZardImageVariants['zShape']>('circle');
  readonly zSize = input<ZardAvatarVariants['zSize'] | number>('default');
  readonly zSrc = input<string>();
  readonly zAlt = input<string>('');
  readonly zFallback = input<string>('');
 
  readonly class = input<string>('');
 
  protected readonly imageError = signal(false);
  protected readonly imageLoaded = signal(false);
 
  protected readonly containerClasses = computed(() => {
    const size = this.zSize();
    const zSize = typeof size === 'number' ? undefined : (size as ZardAvatarVariants['zSize']);
 
    return mergeClasses(avatarVariants({ zShape: this.zShape(), zSize }), this.class());
  });
 
  protected readonly customSize = computed(() => {
    const size = this.zSize();
    return typeof size === 'number' ? `${size}px` : null;
  });
 
  protected readonly imgClasses = computed(() => mergeClasses(imageVariants({ zShape: this.zShape() })));
 
  protected onImageLoad(): void {
    this.imageLoaded.set(true);
    this.imageError.set(false);
  }
 
  protected onImageError(): void {
    this.imageError.set(true);
    this.imageLoaded.set(false);
  }
}
 
avatar.variants.ts
avatar.variants.ts
import { cva, type VariantProps } from 'class-variance-authority';
 
export const avatarVariants = cva(
  'relative flex flex-row items-center justify-center box-content cursor-default bg-muted',
  {
    variants: {
      zSize: {
        sm: 'size-8',
        default: 'size-10',
        md: 'size-12',
        lg: 'size-14',
        xl: 'size-16',
      },
      zShape: {
        circle: 'rounded-full',
        rounded: 'rounded-md',
        square: 'rounded-none',
      },
    },
    defaultVariants: {
      zSize: 'default',
      zShape: 'circle',
    },
  },
);
 
export const imageVariants = cva('relative object-cover object-center w-full h-full z-10', {
  variants: {
    zShape: {
      circle: 'rounded-full',
      rounded: 'rounded-md',
      square: 'rounded-none',
    },
  },
  defaultVariants: {
    zShape: 'circle',
  },
});
 
export const avatarGroupVariants = cva('flex items-center [&_img]:ring-2 [&_img]:ring-background', {
  variants: {
    zOrientation: {
      horizontal: 'flex-row -space-x-3',
      vertical: 'flex-col -space-y-3',
    },
  },
  defaultVariants: {
    zOrientation: 'horizontal',
  },
});
 
export type ZardAvatarVariants = VariantProps<typeof avatarVariants>;
export type ZardImageVariants = VariantProps<typeof imageVariants>;
export type ZardAvatarGroupVariants = VariantProps<typeof avatarGroupVariants>;
 
avatar-group.component.ts
avatar-group.component.ts
import { ChangeDetectionStrategy, Component, computed, input, ViewEncapsulation } from '@angular/core';
 
import type { ClassValue } from 'clsx';
 
import { avatarGroupVariants, ZardAvatarGroupVariants } from './avatar.variants';
import { mergeClasses } from '../../shared/utils/utils';
 
@Component({
  selector: 'z-avatar-group',
  standalone: true,
  template: `<ng-content />`,
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  host: {
    '[class]': 'classes()',
  },
  exportAs: 'zAvatarGroup',
})
export class ZardAvatarGroupComponent {
  readonly zOrientation = input<ZardAvatarGroupVariants['zOrientation']>('horizontal');
  readonly class = input<ClassValue>('');
 
  protected readonly classes = computed(() =>
    mergeClasses(avatarGroupVariants({ zOrientation: this.zOrientation() }), this.class()),
  );
}
 

Examples

basic

ZAZAJDSALU
import { Component } from '@angular/core';
 
import { ZardAvatarGroupComponent } from '../avatar-group.component';
import { ZardAvatarComponent } from '../avatar.component';
 
@Component({
  selector: 'z-demo-avatar-basic',
  imports: [ZardAvatarComponent, ZardAvatarGroupComponent],
  standalone: true,
  template: `
    <z-avatar zSrc="/images/avatar/imgs/avatar_image.jpg" zFallback="ZA" [zSize]="32" />
    <z-avatar zSrc="error-image.png" zFallback="ZA" zSize="sm" />
 
    <z-avatar-group>
      <z-avatar zSrc="/images/avatar/imgs/avatar_image.jpg" zFallback="JD" zSize="sm" />
      <z-avatar zSrc="https://github.com/srizzon.png" zFallback="SA" zSize="sm" />
      <z-avatar zSrc="https://github.com/Luizgomess.png" zFallback="LU" zSize="sm" />
    </z-avatar-group>
  `,
})
export class ZardDemoAvatarBasicComponent {}
 

status

import { Component } from '@angular/core';
 
import { ZardAvatarComponent } from '../avatar.component';
 
@Component({
  selector: 'z-demo-avatar-status',
  imports: [ZardAvatarComponent],
  standalone: true,
  template: `
    <z-avatar zSrc="/images/avatar/imgs/avatar_image.jpg" zAlt="Image" />
    <z-avatar zStatus="online" zSrc="/images/avatar/imgs/avatar_image.jpg" zAlt="Image" />
    <z-avatar zStatus="offline" zSrc="/images/avatar/imgs/avatar_image.jpg" zAlt="Image" />
    <z-avatar zStatus="doNotDisturb" zSrc="/images/avatar/imgs/avatar_image.jpg" zAlt="Image" />
    <z-avatar zStatus="away" zSrc="/images/avatar/imgs/avatar_image.jpg" zAlt="Image" />
  `,
})
export class ZardDemoAvatarStatusComponent {}
 

API Reference

z-avatar Component

Property Description Type Default
[zSize] Avatar size variant sm | default | md | lg | xl | number default
[zShape] Avatar shape circle | rounded | square circle
[zStatus] Status indicator badge online | offline | doNotDisturb | away
[zSrc] Image source URL string
[zAlt] Image alt text for accessibility string ''
[zFallback] Fallback text displayed while loading or on error string ''
[class] Additional CSS classes string ''

z-avatar-group Component

Property Description Type Default
[zOrientation] Layout direction of avatars horizontal | vertical horizontal
[class] Additional CSS classes string ''