Avatar

Material Design 3 avatar component for user representation with multiple sizes, shapes, and status indicators

Avatar

Avatars are visual representations of users or entities. @duskmoon-dev/core provides a complete set of Material Design 3-inspired avatar styles with support for images, initials, icons, and status indicators.

Basic Usage

Avatar with Initials

Avatar with Initials

JD

Avatar with Image

Avatar with Image

User name

Avatar with Icon

Avatar with Icon

Sizes

Six sizes are available, from extra small to 2x large:

Avatar Sizes

XS
SM
MD
LG
XL
2XL

Size Specifications

  • Extra Small (avatar-xs): 1.5rem (24px)
  • Small (avatar-sm): 2rem (32px)
  • Medium (avatar-md): 2.5rem (40px) - default
  • Large (avatar-lg): 3rem (48px)
  • Extra Large (avatar-xl): 4rem (64px)
  • 2X Large (avatar-2xl): 6rem (96px)

Shapes

Three shape variants are available:

Avatar Shapes

User
User
User

Color Variants

Use different color variants to distinguish between users or entity types:

Avatar Color Variants

PR
SE
TE
SU
ER
WA
IN

Color Variant Uses

  • Primary/Secondary/Tertiary: General user avatars with theme colors
  • Success: Active users, online status, verified accounts
  • Error: Suspended accounts, error states
  • Warning: Users requiring attention
  • Info: Informational entities, bots, system users

Status Indicators

Show user online status with status indicators:

Avatar Status Indicators

User
User
User
User

Status with Sizes

Status indicators automatically scale with avatar size:

Status with Different Sizes

User
User

Bordered Avatars

Add a border with outline for emphasis:

Bordered Avatars

User
User

Clickable Avatars

Make avatars interactive for profile navigation:

Clickable Avatars

Clickable avatars include hover effects:

  • Scale up on hover (1.05x)
  • Drop shadow appears
  • Scale down on active (0.98x)

Avatar Groups

Display multiple users in a compact, stacked layout:

Basic Group

Basic Avatar Group

User 1
User 2
User 3
User 4

Dense Group

For more compact spacing:

Dense Avatar Group

User 1
User 2
User 3

Sized Groups

Avatar groups automatically adjust spacing based on avatar size:

Sized Avatar Groups

User 1
User 2
User 3
User 1
User 2
User 3

Overflow Indicator

Show a count for additional users:

Avatar Group with Overflow Indicator

User 1
User 2
User 3
+5

Interactive Groups

Avatars in groups can be made interactive with hover effects:

Interactive Avatar Group

Group avatars automatically:

  • Scale up on hover (1.1x)
  • Move to the front (z-index: 1)
  • Smooth transition animation

Best Practices

Content Guidelines

Initials: Use 1-2 uppercase letters

Avatar Initials Best Practices

JD
AB
john
ABC

Images: Use square images for best results

Avatar Image Best Practices

User name

Icons: Keep icons simple and recognizable

Avatar Icon Best Practices

Accessibility

Always provide descriptive alt text for images:

Accessibility - Descriptive Alt Text

John Doe
John Doe, Senior Developer

For clickable avatars, provide clear labels:

Accessibility - Clickable Avatars

For avatar groups, provide group context:

Accessibility - Avatar Groups

Team member 1
Team member 2

Size Selection

Choose sizes appropriate for your use case:

  • Extra Small/Small (avatar-xs, avatar-sm): Compact lists, mentions, tags
  • Medium (avatar-md): Default for most interfaces, comments, messages
  • Large (avatar-lg): User cards, prominent lists
  • Extra Large/2X Large (avatar-xl, avatar-2xl): Profile pages, headers

Performance

For avatar images:

  1. Optimize images: Use appropriate dimensions (2x the display size for retina)
  2. Use lazy loading: Add loading="lazy" for images below the fold
  3. Provide fallbacks: Always have initials as fallback for failed image loads

Performance Optimization

User name

Framework Examples

React

interface AvatarProps {
  src?: string;
  alt?: string;
  initials?: string;
  size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
  shape?: 'circle' | 'rounded' | 'square';
  status?: 'online' | 'offline' | 'busy' | 'away';
  color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'error' | 'warning' | 'info';
  bordered?: boolean;
  clickable?: boolean;
  onClick?: () => void;
}

export function Avatar({
  src,
  alt = '',
  initials,
  size = 'md',
  shape = 'circle',
  status,
  color,
  bordered = false,
  clickable = false,
  onClick
}: AvatarProps) {
  const className = [
    'avatar',
    `avatar-${size}`,
    `avatar-${shape}`,
    color && `avatar-${color}`,
    status && 'avatar-status',
    status && `avatar-status-${status}`,
    bordered && 'avatar-bordered',
    clickable && 'avatar-clickable'
  ].filter(Boolean).join(' ');

  const Element = clickable ? 'button' : 'div';

  return (
    <Element className={className} onClick={onClick}>
      {src ? (
        <img src={src} alt={alt} className="avatar-image" />
      ) : initials ? (
        initials
      ) : (
        <svg className="avatar-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
        </svg>
      )}
    </Element>
  );
}

// Usage
<Avatar src="https://api.dicebear.com/9.x/avataaars/svg?seed=46" alt="John Doe" size="lg" status="online" />
<Avatar initials="JD" color="primary" clickable onClick={() => console.log('clicked')} />

Vue

<template>
  <component
    :is="clickable ? 'button' : 'div'"
    :class="avatarClass"
    @click="onClick"
  >
    <img
      v-if="src"
      :src="src"
      :alt="alt"
      class="avatar-image"
    />
    <template v-else-if="initials">
      {{ initials }}
    </template>
    <svg
      v-else
      class="avatar-icon"
      fill="none"
      stroke="currentColor"
      viewBox="0 0 24 24"
    >
      <path
        stroke-linecap="round"
        stroke-linejoin="round"
        stroke-width="2"
        d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
      />
    </svg>
  </component>
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps({
  src: String,
  alt: { type: String, default: '' },
  initials: String,
  size: { type: String, default: 'md' },
  shape: { type: String, default: 'circle' },
  status: String,
  color: String,
  bordered: Boolean,
  clickable: Boolean
})

const emit = defineEmits(['click'])

const avatarClass = computed(() => [
  'avatar',
  `avatar-${props.size}`,
  `avatar-${props.shape}`,
  props.color && `avatar-${props.color}`,
  props.status && 'avatar-status',
  props.status && `avatar-status-${props.status}`,
  props.bordered && 'avatar-bordered',
  props.clickable && 'avatar-clickable'
].filter(Boolean).join(' '))

const onClick = () => {
  if (props.clickable) {
    emit('click')
  }
}
</script>

<!-- Usage -->
<Avatar
  src="https://api.dicebear.com/9.x/avataaars/svg?seed=47"
  alt="John Doe"
  size="lg"
  status="online"
/>
<Avatar
  initials="JD"
  color="primary"
  clickable
  @click="handleClick"
/>

Avatar Group Component

// React
interface AvatarGroupProps {
  max?: number;
  size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
  dense?: boolean;
  children: React.ReactNode;
}

export function AvatarGroup({ max, size, dense = false, children }: AvatarGroupProps) {
  const className = [
    'avatar-group',
    size && `avatar-group-${size}`,
    dense && 'avatar-group-dense'
  ].filter(Boolean).join(' ');

  const avatars = React.Children.toArray(children);
  const displayAvatars = max ? avatars.slice(0, max) : avatars;
  const overflowCount = max ? avatars.length - max : 0;

  return (
    <div className={className}>
      {displayAvatars}
      {overflowCount > 0 && (
        <div className={`avatar avatar-overflow ${size ? `avatar-${size}` : ''}`}>
          +{overflowCount}
        </div>
      )}
    </div>
  );
}

// Usage
<AvatarGroup max={3} size="md">
  <Avatar src="https://api.dicebear.com/9.x/avataaars/svg?seed=41" alt="User 1" />
  <Avatar src="https://api.dicebear.com/9.x/avataaars/svg?seed=42" alt="User 2" />
  <Avatar src="https://api.dicebear.com/9.x/avataaars/svg?seed=43" alt="User 3" />
  <Avatar src="https://api.dicebear.com/9.x/avataaars/svg?seed=44" alt="User 4" />
  <Avatar src="https://api.dicebear.com/9.x/avataaars/svg?seed=45" alt="User 5" />
</AvatarGroup>

API Reference

Avatar Classes

ClassDescription
.avatarBase avatar styles (required)
.avatar-imageImage element within avatar
.avatar-iconIcon element within avatar

Size Classes

ClassDimensionsFont Size
.avatar-xs1.5rem (24px)0.625rem
.avatar-sm2rem (32px)0.813rem
.avatar-md2.5rem (40px) - default1rem
.avatar-lg3rem (48px)1.25rem
.avatar-xl4rem (64px)1.5rem
.avatar-2xl6rem (96px)2rem

Shape Classes

ClassDescription
.avatar-circleCircular avatar (default)
.avatar-roundedRounded corners (0.5rem)
.avatar-squareSquare with no rounded corners

Color Classes

ClassDescription
.avatar-primaryPrimary theme color
.avatar-secondarySecondary theme color
.avatar-tertiaryTertiary theme color (default)
.avatar-successSuccess semantic color
.avatar-errorError semantic color
.avatar-warningWarning semantic color
.avatar-infoInfo semantic color

Status Classes

ClassDescription
.avatar-statusEnable status indicator (required for status)
.avatar-status-onlineGreen indicator for online status
.avatar-status-offlineGray indicator for offline status
.avatar-status-busyRed indicator for busy status
.avatar-status-awayYellow indicator for away status

Modifier Classes

ClassDescription
.avatar-borderedAdd border with outline
.avatar-clickableAdd hover/active effects for interaction
.avatar-overflowOverflow indicator for groups (+N more)

Group Classes

ClassDescription
.avatar-groupContainer for stacked avatars
.avatar-group-denseTighter spacing for groups
.avatar-group-xsGroup spacing for xs avatars
.avatar-group-smGroup spacing for sm avatars
.avatar-group-lgGroup spacing for lg avatars
.avatar-group-xlGroup spacing for xl avatars

Combinations

You can combine classes for different effects:

Combined Avatar Classes

User
  • Badge - Notification indicators that can be paired with avatars
  • Card - Container for user profiles with avatars
  • List - Lists with avatar items

See Also