AvesraAvesrabeta

Avatar

Display user profile images with customizable fallback content

Import

import { AvAvatarImports } from '@avesra/angular';

Usage

John DoeJDBlueBJR
import { Component } from '@angular/core';
import { AvAvatarImports } from '@avesra/angular';

@Component({
  selector: 'app-avatar-basic-demo',
  imports: [AvAvatarImports],
  template: `<div class="flex items-center gap-4">
      <span av-avatar>
        <img
          av-avatar-image
          alt="John Doe"
          src="/images/avatars/avatar-man-glasses-salt-pepper.png"
        />
        <span av-avatar-fallback>JD</span>
      </span>
      <span av-avatar>
        <img
          av-avatar-image
          alt="Blue"
          src="/images/avatars/avatar-boy-smiling-blue-shirt.png"
        />
        <span av-avatar-fallback>B</span>
      </span>
      <span av-avatar>
        <span av-avatar-fallback>JR</span>
      </span>
    </div>`,
})
export class AvatarBasicDemo {}

Anatomy

Compose span[av-avatar] with optional img[av-avatar-image] and span[av-avatar-fallback]. The image is a native img host, so standard attributes like src, alt, srcset, and loading work directly.

<span av-avatar>
  <img av-avatar-image />
  <span av-avatar-fallback></span>
</span>

Sizes

Small AvatarSMMedium AvatarMDLarge AvatarLG
import { Component } from '@angular/core';
import { AvAvatarImports } from '@avesra/angular';

@Component({
  selector: 'app-avatar-sizes-demo',
  imports: [AvAvatarImports],
  template: `<div class="flex items-center gap-4">
      <span av-avatar size="sm">
        <img
          av-avatar-image
          alt="Small Avatar"
          src="/images/avatars/avatar-boy-smiling-blue-shirt.png"
        />
        <span av-avatar-fallback>SM</span>
      </span>
      <span av-avatar size="md">
        <img
          av-avatar-image
          alt="Medium Avatar"
          src="/images/avatars/avatar-woman-grey-hair-smiling.png"
        />
        <span av-avatar-fallback>MD</span>
      </span>
      <span av-avatar size="lg">
        <img
          av-avatar-image
          alt="Large Avatar"
          src="/images/avatars/avatar-woman-glasses-auburn-hair.png"
        />
        <span av-avatar-fallback>LG</span>
      </span>
    </div>`,
})
export class AvatarSizesDemo {}

Colors

DFACSCWRDG
import { Component } from '@angular/core';
import { AvAvatarImports } from '@avesra/angular';

@Component({
  selector: 'app-avatar-with-colors-demo',
  imports: [AvAvatarImports],
  template: `<div class="flex items-center gap-4">
      <span av-avatar color="default">
        <span av-avatar-fallback>DF</span>
      </span>
      <span av-avatar color="accent">
        <span av-avatar-fallback>AC</span>
      </span>
      <span av-avatar color="success">
        <span av-avatar-fallback>SC</span>
      </span>
      <span av-avatar color="warning">
        <span av-avatar-fallback>WR</span>
      </span>
      <span av-avatar color="danger">
        <span av-avatar-fallback>DG</span>
      </span>
    </div>`,
})
export class AvatarWithColorsDemo {}

Variants

accent
default
success
warning
danger
letter
AG
AG
AG
AG
AG
letter soft
AG
AG
AG
AG
AG
icon
icon soft
img
Avatar accentA
Avatar defaultD
Avatar successS
Avatar warningW
Avatar dangerD
import { Component } from '@angular/core';
import {
  AvAvatarImports,
  AvSeparatorImports,
} from '@avesra/angular';
import type { AvAvatarColor } from '@avesra/angular';
import { AppIconComponent } from '../../components/app-icon/app-icon.component';

@Component({
  selector: 'app-avatar-variants-demo',
  imports: [
    AppIconComponent,
    AvAvatarImports,
    AvSeparatorImports,
  ],
  template: `<div class="flex flex-col gap-4">
      <div class="flex items-center gap-3">
        <div class="w-24 shrink-0"></div>
        @for (color of colors; track color) {
          <div class="flex w-20 shrink-0 items-center justify-center">
            <span class="text-xs text-muted capitalize">{{ color }}</span>
          </div>
        }
      </div>

      <hr av-separator />

      @for (variant of variants; track variant.label) {
        <div class="flex items-center gap-3">
          <div class="w-24 shrink-0 text-sm text-muted">{{ variant.label }}</div>
          @for (color of colors; track color; let i = $index) {
            <div class="flex w-20 shrink-0 items-center justify-center">
              <span
                av-avatar
                [color]="color"
                [variant]="isSoft(variant.type) ? 'soft' : 'default'"
              >
                @if (variant.type === 'img') {
                  <img
                    av-avatar-image
                    [alt]="'Avatar ' + color"
                    [src]="avatarImages[i]"
                  />
                  <span av-avatar-fallback>{{ color.charAt(0).toUpperCase() }}</span>
                } @else if (isIcon(variant.type)) {
                  <span av-avatar-fallback>
                    <app-icon icon="solar:user-linear" size="16" />
                  </span>
                } @else {
                  <span av-avatar-fallback>{{ variant.content }}</span>
                }
              </span>
            </div>
          }
        </div>
      }
    </div>`,
})
export class AvatarVariantsDemo {
  readonly colors: readonly AvAvatarColor[] = [
    'accent',
    'default',
    'success',
    'warning',
    'danger',
  ];

  readonly avatarImages = ["/images/avatars/avatar-man-glasses-salt-pepper.png","/images/avatars/avatar-woman-grey-hair-smiling.png","/images/avatars/avatar-girl-smiling-blue-dress.png","/images/avatars/avatar-boy-smiling-blue-shirt.png","/images/avatars/avatar-woman-glasses-auburn-hair.png"];

  readonly variants: readonly {
    label: string;
    type: 'letter' | 'letter-soft' | 'icon' | 'icon-soft' | 'img';
    content?: string;
  }[] = [
    { label: 'letter', type: 'letter', content: 'AG' },
    { label: 'letter soft', type: 'letter-soft', content: 'AG' },
    { label: 'icon', type: 'icon' },
    { label: 'icon soft', type: 'icon-soft' },
    { label: 'img', type: 'img' },
  ];

  isSoft(type: string): boolean {
    return type.includes('soft');
  }

  isIcon(type: string): boolean {
    return type === 'icon' || type === 'icon-soft';
  }
}

Fallback Content

JDDelayed AvatarNA GB
import { Component } from '@angular/core';
import { AvAvatarImports } from '@avesra/angular';
import { AppIconComponent } from '../../components/app-icon/app-icon.component';

@Component({
  selector: 'app-avatar-fallback-demo',
  imports: [
    AppIconComponent,
    AvAvatarImports,
  ],
  template: `<div class="flex items-center gap-4">
      <span av-avatar>
        <span av-avatar-fallback>JD</span>
      </span>
      <span av-avatar>
        <span av-avatar-fallback>
          <app-icon icon="solar:user-linear" size="16" />
        </span>
      </span>
      <span av-avatar>
        <img
          av-avatar-image
          alt="Delayed Avatar"
          src="https://invalid-url-to-show-fallback.com/image.jpg"
        />
        <span av-avatar-fallback [delay-ms]="600">NA</span>
      </span>
      <span av-avatar>
        <span
          av-avatar-fallback
          class="border-none bg-gradient-to-br from-pink-500 to-purple-500 text-white"
        >
          GB
        </span>
      </span>
    </div>`,
})
export class AvatarFallbackDemo {}

Avatar Group

John DoeJDKate WilsonKWEmily ChenECMichael BrownMB
John DoeJDKate WilsonKWEmily ChenEC+2
import { Component } from '@angular/core';
import { AvAvatarImports } from '@avesra/angular';

@Component({
  selector: 'app-avatar-group-demo',
  imports: [AvAvatarImports],
  template: `<div class="flex flex-col gap-6">
      <div class="flex -space-x-2">
        @for (user of basicUsers; track user.id) {
          <span av-avatar class="ring-2 ring-background">
            <img av-avatar-image [alt]="user.name" [src]="user.image" />
            <span av-avatar-fallback>{{ initials(user.name) }}</span>
          </span>
        }
      </div>

      <div class="flex -space-x-2">
        @for (user of counterUsers; track user.id) {
          <span av-avatar class="ring-2 ring-background">
            <img av-avatar-image [alt]="user.name" [src]="user.image" />
            <span av-avatar-fallback>{{ initials(user.name) }}</span>
          </span>
        }
        <span av-avatar class="ring-2 ring-background">
          <span av-avatar-fallback class="text-xs">+{{ overflowCount }}</span>
        </span>
      </div>
    </div>`,
})
export class AvatarGroupDemo {
  readonly users = [
  {
    "id": 1,
    "image": "/images/avatars/avatar-man-glasses-salt-pepper.png",
    "name": "John Doe"
  },
  {
    "id": 2,
    "image": "/images/avatars/avatar-woman-grey-hair-smiling.png",
    "name": "Kate Wilson"
  },
  {
    "id": 3,
    "image": "/images/avatars/avatar-girl-smiling-blue-dress.png",
    "name": "Emily Chen"
  },
  {
    "id": 4,
    "image": "/images/avatars/avatar-boy-smiling-blue-shirt.png",
    "name": "Michael Brown"
  },
  {
    "id": 5,
    "image": "/images/avatars/avatar-woman-glasses-auburn-hair.png",
    "name": "Olivia Davis"
  }
];

  readonly basicUsers = this.users.slice(0, 4);
  readonly counterUsers = this.users.slice(0, 3);
  readonly overflowCount = this.users.length - 3;

  initials(name: string): string {
    return name
      .split(' ')
      .map((part) => part[0])
      .join('');
  }
}

Styling

Passing Tailwind CSS classes

Pass utility classes on the avatar host and its parts to customize size, shape, and decoration.

Extra LargeXLSquare AvatarSQ
Gradient BorderGB
Online UserON
import { Component } from '@angular/core';
import { AvAvatarImports } from '@avesra/angular';

@Component({
  selector: 'app-avatar-custom-styles-demo',
  imports: [AvAvatarImports],
  template: `<div class="flex items-center gap-4">
      <span av-avatar class="size-16">
        <img
          av-avatar-image
          alt="Extra Large"
          src="/images/avatars/avatar-boy-smiling-blue-shirt.png"
        />
        <span av-avatar-fallback>XL</span>
      </span>

      <span av-avatar class="rounded-lg">
        <img
          av-avatar-image
          alt="Square Avatar"
          src="/images/avatars/avatar-woman-grey-hair-smiling.png"
        />
        <span av-avatar-fallback class="rounded-lg">SQ</span>
      </span>

      <span
        av-avatar
        class="bg-cover bg-center p-0.5"
        [style.background-image]="'url(/images/gradients/gradient-warm-orange-yellow-red.png)'"
      >
        <div class="size-full rounded-full bg-background p-0.5">
          <img
            av-avatar-image
            class="rounded-full"
            alt="Gradient Border"
            src="/images/avatars/avatar-woman-glasses-auburn-hair.png"
          />
          <span av-avatar-fallback class="border-none">GB</span>
        </div>
      </span>

      <div class="relative">
        <span av-avatar>
          <img
            av-avatar-image
            alt="Online User"
            src="/images/avatars/avatar-man-glasses-salt-pepper.png"
          />
          <span av-avatar-fallback>ON</span>
        </span>
        <span
          class="absolute right-0 bottom-0 size-3 rounded-full bg-green-500 ring-2 ring-background"
        ></span>
      </div>
    </div>`,
})
export class AvatarCustomStylesDemo {}

Customizing the component classes

To customize the Avatar classes, use the @layer components directive. Learn more.

@layer components {
  .av-avatar {
    @apply size-16 border-2 border-accent;
  }

  .av-avatar__fallback {
    @apply bg-linear-to-br from-purple-500 to-pink-500;
  }
}

Avesra follows the BEM methodology so component variants and states stay reusable and easy to customize.

CSS Classes

The Avatar component uses these CSS classes:

Base Classes

  • .av-avatar — Base container with default size (size-10)
  • .av-avatar__image — Image element with aspect-square sizing
  • .av-avatar__fallback — Fallback container with centered content

Size Modifiers

  • .av-avatar--sm — Small avatar (size-8)
  • .av-avatar--md — Medium avatar (default, no additional styles)
  • .av-avatar--lg — Large avatar (size-12)

Variant Modifiers

  • .av-avatar--soft — Soft variant with lighter background

Color Modifiers

  • .av-avatar__fallback--default — Default text color
  • .av-avatar__fallback--accent — Accent text color
  • .av-avatar__fallback--success — Success text color
  • .av-avatar__fallback--warning — Warning text color
  • .av-avatar__fallback--danger — Danger text color

API Reference

Root options live on span[av-avatar]. Image attributes bind on img[av-avatar-image]; fallback options on span[av-avatar-fallback].

PropTypeDefaultDescription
color'default' | 'accent' | 'success' | 'warning' | 'danger''default'Fallback color theme (span[av-avatar]).
size'sm' | 'md' | 'lg''md'Avatar size (span[av-avatar]).
variant'default' | 'soft''default'Visual style variant (span[av-avatar]).
srcstring—Image source URL (img[av-avatar-image]).
srcsetstring—Responsive image `srcset` (img[av-avatar-image]).
sizesstring—Responsive image `sizes` hint (img[av-avatar-image]).
altstring—Accessible alternative text (img[av-avatar-image]).
crossorigin'anonymous' | 'use-credentials'—CORS setting for the image request (img[av-avatar-image]).
loading'eager' | 'lazy'—Native lazy loading attribute (img[av-avatar-image]).
delay-msnumber0Delay before showing fallback while the image loads (span[av-avatar-fallback]).
color'default' | 'accent' | 'success' | 'warning' | 'danger' | undefined—Override color from parent. Inherits from av-avatar when omitted (span[av-avatar-fallback]).

Made with ❤ by SyntaxHertz. Open source and available on GitHub.