Skip to content
v2.5.0
English
Русский
Documentation

Avatar

Avatar renders a user or entity representation with support for image, fallback, and icon content.
JD
avatar.tsx · 3 lines
import { Avatar, AvatarFallback } from '@vega-ui/react';

<Avatar size='lg'><AvatarFallback>JD</AvatarFallback></Avatar>
Browser support
Widely available
  • Chrome 111
  • Edge 111
  • Firefox 113
  • Safari 15.4
  • Safari on iOS 15.4
Bundle size
Tested in
14 tests

Summary

Avatar renders a user or entity representation with support for image, fallback, and icon content. It is the identity-display primitive for one person or entity, not a generic decorative circle.

Imports

import {
  Avatar,
  AvatarImage,
  AvatarFallback,
  AvatarIcon,
  type AvatarProps,
  type AvatarSize,
  type AvatarVariant,
} from '@vega-ui/react';

Exported Types

  • AvatarProps
  • AvatarImageProps
  • AvatarFallbackProps
  • AvatarIconProps
  • AvatarSize
  • AvatarVariant

Minimal Composition

minimal-composition.tsx · 14 lines
import { Avatar, AvatarFallback, AvatarImage } from '@vega-ui/react';

const portrait = (hue: number) => `data:image/svg+xml,${encodeURIComponent(`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'><rect width='64' height='64' fill='hsl(${hue} 60% 82%)'/><circle cx='32' cy='25' r='11' fill='hsl(${hue} 35% 42%)'/><path d='M12 64c1-13 9-21 20-21s19 8 20 21z' fill='hsl(${hue} 35% 42%)'/></svg>`)}`;

const photo = portrait(210);

export default function MinimalComposition() {
  return (
    <Avatar role='img' aria-label='Jane Doe'>
      <AvatarImage src={photo} alt='' />
      <AvatarFallback>JD</AvatarFallback>
    </Avatar>

Required Parts

  • Avatar: root surface

Optional Parts

  • AvatarImage: image content
  • AvatarFallback: text fallback
  • AvatarIcon: icon fallback

Composition Order

  1. Avatar
  2. AvatarImage
  3. AvatarFallback or AvatarIcon

Variants

  • Sizes: 2xs, xs, sm, md, lg, xl, 2xl
  • Variants: primary, secondary
  • Content variants: image, fallback initials, icon

Edge Cases

  • Always provide meaningful alt text for informative avatar images.
  • Include fallback content for missing or slow-loading images.
  • Very small sizes need short fallback text to avoid overflow.
  • Decide explicitly whether the avatar is informative identity content or purely decorative context in each usage.

Common Mistakes

  • Rendering an avatar image without fallback.
  • Using decorative avatars without deciding whether they should be announced.
  • Letting fallback initials overflow in small sizes.

Examples

Basic

Basic: member list with photos and initials

The name is already visible next to each avatar, so the avatar is decorative: aria-hidden on the root and alt='' on the image. Members without a photo get initials, and a deactivated member uses variant='secondary'.

member-list.tsx · 31 lines
import { Avatar, AvatarFallback, AvatarImage, Text } from '@vega-ui/react';

const portrait = (hue: number) => `data:image/svg+xml,${encodeURIComponent(`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'><rect width='64' height='64' fill='hsl(${hue} 60% 82%)'/><circle cx='32' cy='25' r='11' fill='hsl(${hue} 35% 42%)'/><path d='M12 64c1-13 9-21 20-21s19 8 20 21z' fill='hsl(${hue} 35% 42%)'/></svg>`)}`;

const members = [
  { name: 'Maria Chen', email: 'maria@northwind.io', initials: 'MC', photo: portrait(210), active: true },
  { name: 'Omar Haddad', email: 'omar@northwind.io', initials: 'OH', photo: portrait(28), active: true },
  { name: 'Lena Fischer', email: 'lena@northwind.io', initials: 'LF', photo: '', active: true },
  { name: 'Tom Becker', email: 'tom@northwind.io', initials: 'TB', photo: '', active: false },
];

export default function MemberList() {

Basic: bots, teams and organizations

AvatarIcon stands in for entities that have no face or initials. variant='secondary' keeps them visually apart from people.

generic-entities.tsx · 27 lines
import { Avatar, AvatarIcon, Text } from '@vega-ui/react';
import { Bot, Building2, Users } from '@vega-ui/icons';

export default function GenericEntities() {
  return (
    <ul style={{ listStyle: 'none', margin: 0, padding: 0, display: 'grid', gap: 'var(--spacing-6)', width: '100%' }}>
      <li style={{ display: 'flex', alignItems: 'center', gap: 'var(--spacing-6)' }}>
        <Avatar size='sm' variant='secondary' aria-hidden='true'>
          <AvatarIcon><Bot /></AvatarIcon>
        </Avatar>
        <Text size={3}>Release bot merged 3 pull requests</Text>
      </li>

Form/Integration

Form/Integration: profile photo upload with preview

A native file input feeds an object URL into AvatarImage for an instant preview; the URL is revoked when it changes. On submit the file is read from FormData, and reset brings back the initials.

photo-upload.tsx · 54 lines
import { ChangeEvent, FormEvent, useEffect, useRef, useState } from 'react';
import { Avatar, AvatarFallback, AvatarImage, Button, Text } from '@vega-ui/react';

export default function PhotoUpload() {
  const inputRef = useRef<HTMLInputElement>(null);
  const [preview, setPreview] = useState('');
  const [result, setResult] = useState('');

  useEffect(() => {
    if (preview === '') return;
    return () => URL.revokeObjectURL(preview);
  }, [preview]);

Layout/Overlay

Layout/Overlay: comment thread with long text

The avatar is top-aligned with multi-line comments. In a flex row it can be squeezed by long text, so it gets flex-shrink: 0, and the text column gets min-width: 0 with overflow-wrap: anywhere for the long URL.

comment-thread.tsx · 45 lines
import { Avatar, AvatarFallback, AvatarImage, Text } from '@vega-ui/react';

const portrait = (hue: number) => `data:image/svg+xml,${encodeURIComponent(`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'><rect width='64' height='64' fill='hsl(${hue} 60% 82%)'/><circle cx='32' cy='25' r='11' fill='hsl(${hue} 35% 42%)'/><path d='M12 64c1-13 9-21 20-21s19 8 20 21z' fill='hsl(${hue} 35% 42%)'/></svg>`)}`;

const comments = [
  {
    id: 1,
    author: 'Maria Chen',
    initials: 'MC',
    photo: portrait(210),
    time: '10:24',
    text: 'The retry policy should back off exponentially, otherwise a failing endpoint gets hammered every few seconds and we fill the queue with duplicate deliveries for the same event.',

Error

Error: image that fails to load

AvatarImage stays hidden until it loads. When it fails, the initials from AvatarFallback show through, or fallbackSrc is tried first if it is set. Each avatar is named once with role='img' and aria-label, so the initials are not read as a second name.

image-fallbacks.tsx · 29 lines
import { Avatar, AvatarFallback, AvatarImage, Text } from '@vega-ui/react';

const portrait = (hue: number) => `data:image/svg+xml,${encodeURIComponent(`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'><rect width='64' height='64' fill='hsl(${hue} 60% 82%)'/><circle cx='32' cy='25' r='11' fill='hsl(${hue} 35% 42%)'/><path d='M12 64c1-13 9-21 20-21s19 8 20 21z' fill='hsl(${hue} 35% 42%)'/></svg>`)}`;

const photo = portrait(150);
const placeholder = portrait(220);
const broken = 'data:image/png;base64,broken';

const cases = [
  { label: 'Image loads', name: 'Priya Nair', initials: 'PN', src: photo, fallbackSrc: undefined },
  { label: 'Image fails → initials', name: 'Diego Alvarez', initials: 'DA', src: broken, fallbackSrc: undefined },
  { label: 'Image fails → fallbackSrc', name: 'Sara Lindqvist', initials: 'SL', src: broken, fallbackSrc: placeholder },

Edge

Edge: initials from real-world names

Initials are derived from the first and last word, with a single word giving two letters and an empty name falling back to an icon. Array.from keeps non-Latin and accented letters intact, and long names are truncated next to the avatar.

initials.tsx · 41 lines
import { Avatar, AvatarFallback, AvatarIcon, Text } from '@vega-ui/react';
import { User } from '@vega-ui/icons';

const getInitials = (name: string) => {
  const words = name.trim().split(/\s+/).filter((word) => word !== '');
  if (words.length === 0) return '';
  if (words.length === 1) return Array.from(words[0]).slice(0, 2).join('').toLocaleUpperCase();
  const first = Array.from(words[0])[0];
  const last = Array.from(words[words.length - 1])[0];
  return `${first}${last}`.toLocaleUpperCase();
};

Anatomy

Overview

Avatar is a compound component because the root, image, fallback, and icon parts cooperate to represent one entity through a prioritized content model.

Required Parts

Avatar

Required. Owns size and variant styling.

Optional Parts

AvatarImage

Optional primary image content.

AvatarFallback

Optional text fallback, often initials.

AvatarIcon

Optional icon fallback for generic entity representation.

Composition Order

  1. Avatar
  2. AvatarImage
  3. AvatarFallback or AvatarIcon

Valid Composition Patterns

member-list.tsx · 31 lines
import { Avatar, AvatarFallback, AvatarImage, Text } from '@vega-ui/react';

const portrait = (hue: number) => `data:image/svg+xml,${encodeURIComponent(`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'><rect width='64' height='64' fill='hsl(${hue} 60% 82%)'/><circle cx='32' cy='25' r='11' fill='hsl(${hue} 35% 42%)'/><path d='M12 64c1-13 9-21 20-21s19 8 20 21z' fill='hsl(${hue} 35% 42%)'/></svg>`)}`;

const members = [
  { name: 'Maria Chen', email: 'maria@northwind.io', initials: 'MC', photo: portrait(210), active: true },
  { name: 'Omar Haddad', email: 'omar@northwind.io', initials: 'OH', photo: portrait(28), active: true },
  { name: 'Lena Fischer', email: 'lena@northwind.io', initials: 'LF', photo: '', active: true },
  { name: 'Tom Becker', email: 'tom@northwind.io', initials: 'TB', photo: '', active: false },
];

export default function MemberList() {

Invalid Composition Patterns

Image without any fallback plan

Broken or slow-loading images leave the entity without a stable representation.

Long fallback text in tiny sizes

The avatar becomes visually unstable and harder to scan.