Avatar

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

Status Contract

Canonical status classes are avatar-status-online, avatar-status-offline, avatar-status-busy, avatar-status-away. avatar-status is a compatibility composition marker; avatar-online / avatar-offline remain supported aliases. Image/initials masking happens inside the Avatar; status remains unclipped. Use visible labels, not color alone. A pseudo-element has no accessible name.

Indicator composition

LM Online
Luna Moon - Online

Use an indicator-item child OR the legacy pseudo-status class, not both. Indicator is in the core aggregate; individual Avatar consumers must also import Indicator and Badge CSS.

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 size classes are available. The default Avatar is medium at 3rem (48px). avatar-xl and avatar-2xl both render at 6rem (96px); avatar-2xl is a compatibility alias that preserves the existing extra-large size.

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): 3rem (48px) - default
  • Large (avatar-lg): 4rem (64px)
  • Extra Large (avatar-xl): 6rem (96px)
  • 2X Large (avatar-2xl): 6rem (96px), equivalent to avatar-xl

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

Class Description
.avatar Base avatar styles (required)
.avatar-image Image element within avatar
.avatar-icon Icon element within avatar

Size Classes

Class Dimensions Font Size
.avatar-xs 1.5rem (24px) 0.625rem
.avatar-sm 2rem (32px) 0.75rem
.avatar-md 3rem (48px) - default 1rem
.avatar-lg 4rem (64px) 1.5rem
.avatar-xl 6rem (96px) 2rem
.avatar-2xl 6rem (96px), equivalent to .avatar-xl 2rem

Shape Classes

Class Description
.avatar-circle Circular avatar (default)
.avatar-rounded Rounded corners (0.5rem)
.avatar-square Square with no rounded corners

Color Classes

Class Description
.avatar-primary Primary theme color
.avatar-secondary Secondary theme color
.avatar-tertiary Tertiary theme color (default)
.avatar-success Success semantic color
.avatar-error Error semantic color
.avatar-warning Warning semantic color
.avatar-info Info semantic color

Status Classes

Class Description
.avatar-status Enable status indicator (required for status)
.avatar-status-online Green indicator for online status
.avatar-status-offline Gray indicator for offline status
.avatar-status-busy Red indicator for busy status
.avatar-status-away Yellow indicator for away status

Modifier Classes

Class Description
.avatar-bordered Add border with outline
.avatar-clickable Add hover/active effects for interaction
.avatar-overflow Overflow indicator for groups (+N more)

Group Classes

Class Description
.avatar-group Container for stacked avatars
.avatar-group-dense Tighter spacing for groups
.avatar-group-xs Group spacing for xs avatars
.avatar-group-sm Group spacing for sm avatars
.avatar-group-lg Group spacing for lg avatars
.avatar-group-xl Group 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