Skip to content

Avatar

An image with a fallback that stands in while it loads, and stays if it never does.

View source View as Markdown

Avatar renders a profile picture and holds a fallback behind it until the image has loaded. Useful wherever the picture might be missing, slow or broken, and initials should stand in.

RSimage
CJbroken src
MWno image
AAAAAAAAAA
App.vue
<template>
  <div class="flex flex-col items-center gap-8">
    <div class="flex items-start gap-4">
      <div
        v-for="person in people"
        :key="person.initials"
        class="flex flex-col items-center gap-2"
      >
        <Avatar.Root :class="[avatar, sizes[2]!.box, solid]">
          <Avatar.Image
            v-if="person.src"
            :src="person.src"
            :alt="person.alt"
            class="size-full"
          />
          <Avatar.Fallback :class="initials">
            {{ person.initials }}
          </Avatar.Fallback>
        </Avatar.Root>

        <span class="type-component-2xs text-surface-muted">
          {{ person.label }}
        </span>
      </div>
    </div>

    <div class="flex items-center gap-4">
      <Avatar.Root
        v-for="size in sizes"
        :key="size.name"
        :class="[avatar, size.box, translucent]"
      >
        <Avatar.Fallback :class="initials">AA</Avatar.Fallback>
      </Avatar.Root>
    </div>
  </div>
</template>

<script setup lang="ts">
import { Avatar } from '@maas/mirror/vue/Avatar'

const people = [
  { initials: 'RS', alt: 'Robin Vey', src: '/robin.jpg', label: 'image' },
  { initials: 'CJ', alt: '', src: '/missing.png', label: 'broken src' },
  { initials: 'MW', alt: '', src: '', label: 'no image' },
]

const sizes = [
  { name: 'xs', box: 'size-8 rounded-component-sm type-component-xs' },
  { name: 'sm', box: 'size-10 rounded-component-md type-component-md' },
  { name: 'md', box: 'size-12 rounded-component-lg type-component-xl' },
  { name: 'lg', box: 'size-14 rounded-component-xl type-component-3xl' },
  { name: 'xl', box: 'size-16 rounded-component-2xl type-component-5xl' },
]

const avatar = 'flex items-center justify-center overflow-hidden'

const solid = 'bg-primary-solid text-primary-on-solid'
const translucent = 'bg-primary-subtle text-primary-on-subtle'

const initials = 'font-medium tracking-[0.02em] leading-none'
</script>

The second avatar fails to load, and the third has no image at all.

Usage guidelines

  • Size Avatar.Root rather than Avatar.Image, because nothing loads on the server: a server-rendered avatar is the fallback, and the image only arrives after hydration.should
  • The server-rendered markup holds no image, so the alt text is not in the HTML a crawler reads. Where that matters, name the surrounding link or heading instead of relying on the avatar.should
  • Put the name on the image’s alt, or leave alt empty and name the surrounding link, so the initials are never read out twice.must