Skip to content

Avatar

Display user or entity profile images with a fallback when the image is missing or still loading.

Import

vue
<script setup lang="ts">
import { Avatar, AvatarFallback, AvatarImage } from '@heroui-vue/vue'
</script>

Usage

Basic

John DoeJDBlueBJR

<template>
  <div class="demo-avatar-row">
    <Avatar>
      <AvatarImage
        alt="John Doe"
        src="https://img.heroui.chat/image/avatar?w=400&h=400&u=3"
      />
      <AvatarFallback>JD</AvatarFallback>
    </Avatar>
    <Avatar>
      <AvatarImage
        alt="Blue"
        src="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/blue.jpg"
      />
      <AvatarFallback>B</AvatarFallback>
    </Avatar>
    <Avatar>
      <AvatarFallback>JR</AvatarFallback>
    </Avatar>
  </div>
</template>

<script setup lang="ts">
import { Avatar, AvatarFallback, AvatarImage } from '@heroui-vue/vue'
</script>

<style lang="less">
.demo-avatar-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
}
</style>

Anatomy

vue
<template>
  <Avatar>
    <AvatarImage src="..." alt="..." />
    <AvatarFallback>JD</AvatarFallback>
  </Avatar>
</template>

Sizes

Small AvatarSMMedium AvatarMDLarge AvatarLG

<template>
  <div class="demo-avatar-row">
    <Avatar size="sm">
      <AvatarImage
        alt="Small Avatar"
        src="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/blue.jpg"
      />
      <AvatarFallback>SM</AvatarFallback>
    </Avatar>
    <Avatar size="md">
      <AvatarImage
        alt="Medium Avatar"
        src="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/purple.jpg"
      />
      <AvatarFallback>MD</AvatarFallback>
    </Avatar>
    <Avatar size="lg">
      <AvatarImage
        alt="Large Avatar"
        src="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/red.jpg"
      />
      <AvatarFallback>LG</AvatarFallback>
    </Avatar>
  </div>
</template>

<script setup lang="ts">
import { Avatar, AvatarFallback, AvatarImage } from '@heroui-vue/vue'
</script>

<style lang="less">
.demo-avatar-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
}
</style>

Colors

DFACSCWRDG

<template>
  <div class="demo-avatar-row">
    <Avatar
      v-for="item in colors"
      :key="item.color"
      :color="item.color"
    >
      <AvatarFallback>{{ item.label }}</AvatarFallback>
    </Avatar>
  </div>
</template>

<script setup lang="ts">
import { Avatar, AvatarFallback } from '@heroui-vue/vue'

const colors = [
  { color: 'default', label: 'DF' },
  { color: 'accent', label: 'AC' },
  { color: 'success', label: 'SC' },
  { color: 'warning', label: 'WR' },
  { color: 'danger', label: 'DG' },
] as const
</script>

<style lang="less">
.demo-avatar-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
}
</style>

Variants

accent
default
success
warning
danger
letter
AG
DG
SG
WG
DG
letter soft
AG
DG
SG
WG
DG
icon
icon soft
img
Avatar accentA
Avatar defaultD
Avatar successS
Avatar warningW
Avatar dangerD

<template>
  <div class="demo-avatar-variants">
    <div class="demo-avatar-variant-row">
      <div class="demo-avatar-variant-label" />
      <div
        v-for="color in colors"
        :key="color"
        class="demo-avatar-variant-cell"
      >
        <span class="demo-avatar-variant-header">{{ color }}</span>
      </div>
    </div>

    <Separator />

    <div
      v-for="row in rows"
      :key="row.label"
      class="demo-avatar-variant-row"
    >
      <div class="demo-avatar-variant-label">
        {{ row.label }}
      </div>
      <div
        v-for="(color, colorIndex) in colors"
        :key="color"
        class="demo-avatar-variant-cell"
      >
        <Avatar
          :color="color"
          :variant="row.soft ? 'soft' : undefined"
        >
          <AvatarImage
            v-if="row.type === 'img'"
            :alt="`Avatar ${color}`"
            :src="images[colorIndex]"
          />
          <AvatarFallback>
            <PersonIcon v-if="row.type === 'icon'" />
            <template v-else>
              {{ color.slice(0, 1).toUpperCase() }}{{ row.type === 'img' ? '' : 'G' }}
            </template>
          </AvatarFallback>
        </Avatar>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { defineComponent, h } from 'vue'
import { Avatar, AvatarFallback, AvatarImage, Separator } from '@heroui-vue/vue'

const colors = ['accent', 'default', 'success', 'warning', 'danger'] as const
const images = [
  'https://img.heroui.chat/image/avatar?w=400&h=400&u=3',
  'https://img.heroui.chat/image/avatar?w=400&h=400&u=4',
  'https://img.heroui.chat/image/avatar?w=400&h=400&u=5',
  'https://img.heroui.chat/image/avatar?w=400&h=400&u=8',
  'https://img.heroui.chat/image/avatar?w=400&h=400&u=16',
]

const rows = [
  { label: 'letter', type: 'letter', soft: false },
  { label: 'letter soft', type: 'letter', soft: true },
  { label: 'icon', type: 'icon', soft: false },
  { label: 'icon soft', type: 'icon', soft: true },
  { label: 'img', type: 'img', soft: false },
] as const

const PersonIcon = defineComponent({
  setup() {
    return () =>
      h(
        'svg',
        {
          viewBox: '0 0 24 24',
          fill: 'none',
          stroke: 'currentColor',
          'stroke-width': '2',
          'stroke-linecap': 'round',
          'stroke-linejoin': 'round',
          'aria-hidden': 'true',
        },
        [
          h('path', { d: 'M20 21a8 8 0 0 0-16 0' }),
          h('path', { d: 'M12 13a5 5 0 1 0 0-10 5 5 0 0 0 0 10Z' }),
        ],
      )
  },
})
</script>

<style lang="less">
.demo-avatar-variants {
  display: flex;
  max-width: 100%;
  flex-direction: column;
  gap: 1rem;
  overflow-x: auto;
  text-align: left;
}

.demo-avatar-variant-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.demo-avatar-variant-label {
  width: 6rem;
  flex-shrink: 0;
  color: var(--color-muted-foreground);
  font-size: 0.875rem;
}

.demo-avatar-variant-cell {
  display: flex;
  width: 5rem;
  flex-shrink: 0;
  justify-content: center;
}

.demo-avatar-variant-header {
  color: var(--color-muted-foreground);
  font-size: 0.75rem;
  text-transform: capitalize;
}

.avatar svg {
  width: 1rem;
  height: 1rem;
}
</style>

Fallback Content

JDDelayed Avatar GB

<template>
  <div class="demo-avatar-row">
    <Avatar>
      <AvatarFallback>JD</AvatarFallback>
    </Avatar>

    <Avatar>
      <AvatarFallback>
        <PersonIcon />
      </AvatarFallback>
    </Avatar>

    <Avatar>
      <AvatarImage
        alt="Delayed Avatar"
        src="https://invalid-url-to-show-fallback.com/image.jpg"
      />
      <AvatarFallback :delay-ms="600">
        NA
      </AvatarFallback>
    </Avatar>

    <Avatar>
      <AvatarFallback class="demo-avatar-gradient-fallback">
        GB
      </AvatarFallback>
    </Avatar>
  </div>
</template>

<script setup lang="ts">
import { defineComponent, h } from 'vue'
import { Avatar, AvatarFallback, AvatarImage } from '@heroui-vue/vue'

const PersonIcon = defineComponent({
  setup() {
    return () =>
      h(
        'svg',
        {
          viewBox: '0 0 24 24',
          fill: 'none',
          stroke: 'currentColor',
          'stroke-width': '2',
          'stroke-linecap': 'round',
          'stroke-linejoin': 'round',
          'aria-hidden': 'true',
        },
        [
          h('path', { d: 'M20 21a8 8 0 0 0-16 0' }),
          h('path', { d: 'M12 13a5 5 0 1 0 0-10 5 5 0 0 0 0 10Z' }),
        ],
      )
  },
})
</script>

<style lang="less">
.demo-avatar-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
}

.avatar svg {
  width: 1rem;
  height: 1rem;
}

.demo-avatar-gradient-fallback {
  background: linear-gradient(135deg, rgb(236 72 153), rgb(168 85 247));
  color: white;
}
</style>

Avatar Group

John DoeJDKate WilsonKWEmily ChenECMichael BrownMB
John DoeJDKate WilsonKWEmily ChenEC +2

<template>
  <div class="demo-avatar-stack">
    <div class="demo-avatar-group">
      <Avatar
        v-for="user in users.slice(0, 4)"
        :key="user.id"
        class="demo-avatar-ring"
      >
        <AvatarImage
          :alt="user.name"
          :src="user.image"
        />
        <AvatarFallback>{{ initials(user.name) }}</AvatarFallback>
      </Avatar>
    </div>

    <div class="demo-avatar-group">
      <Avatar
        v-for="user in users.slice(0, 3)"
        :key="user.id"
        class="demo-avatar-ring"
      >
        <AvatarImage
          :alt="user.name"
          :src="user.image"
        />
        <AvatarFallback>{{ initials(user.name) }}</AvatarFallback>
      </Avatar>
      <Avatar class="demo-avatar-ring">
        <AvatarFallback class="demo-avatar-counter">
          +{{ users.length - 3 }}
        </AvatarFallback>
      </Avatar>
    </div>
  </div>
</template>

<script setup lang="ts">
import { Avatar, AvatarFallback, AvatarImage } from '@heroui-vue/vue'

const users = [
  {
    id: 1,
    image: 'https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/blue.jpg',
    name: 'John Doe',
  },
  {
    id: 2,
    image: 'https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/green.jpg',
    name: 'Kate Wilson',
  },
  {
    id: 3,
    image: 'https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/purple.jpg',
    name: 'Emily Chen',
  },
  {
    id: 4,
    image: 'https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/orange.jpg',
    name: 'Michael Brown',
  },
  {
    id: 5,
    image: 'https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/red.jpg',
    name: 'Olivia Davis',
  },
]

const initials = (name: string) =>
  name
    .split(' ')
    .map((part) => part[0])
    .join('')
</script>

<style lang="less">
.demo-avatar-stack {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.demo-avatar-group {
  display: flex;
}

.demo-avatar-group > .avatar + .avatar {
  margin-left: -0.5rem;
}

.demo-avatar-ring {
  box-shadow: 0 0 0 2px var(--vp-c-bg);
}

.demo-avatar-counter {
  font-size: 0.75rem;
}
</style>

Custom Styles

Extra LargeXLSquare Avatar SQ
Gradient BorderGB
Online UserON

<template>
  <div class="demo-avatar-row">
    <Avatar class="demo-avatar-xl">
      <AvatarImage
        alt="Extra Large"
        src="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/blue.jpg"
      />
      <AvatarFallback>XL</AvatarFallback>
    </Avatar>

    <Avatar class="demo-avatar-square">
      <AvatarImage
        alt="Square Avatar"
        src="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/purple.jpg"
      />
      <AvatarFallback class="demo-avatar-square">
        SQ
      </AvatarFallback>
    </Avatar>

    <Avatar class="demo-avatar-gradient-border">
      <div class="demo-avatar-gradient-inner">
        <AvatarImage
          alt="Gradient Border"
          class="demo-avatar-rounded-image"
          src="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/red.jpg"
        />
        <AvatarFallback>GB</AvatarFallback>
      </div>
    </Avatar>

    <div class="demo-avatar-status-wrap">
      <Avatar>
        <AvatarImage
          alt="Online User"
          src="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/orange.jpg"
        />
        <AvatarFallback>ON</AvatarFallback>
      </Avatar>
      <span class="demo-avatar-status" />
    </div>
  </div>
</template>

<script setup lang="ts">
import { Avatar, AvatarFallback, AvatarImage } from '@heroui-vue/vue'
</script>

<style lang="less">
.demo-avatar-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
}

.demo-avatar-xl {
  width: 4rem;
  height: 4rem;
}

.demo-avatar-square {
  border-radius: 0.5rem;
}

.demo-avatar-gradient-border {
  padding: 0.125rem;
  background: linear-gradient(45deg, rgb(236 72 153), rgb(234 179 8));
}

.demo-avatar-gradient-inner {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: 999px;
  background: var(--vp-c-bg);
}

.demo-avatar-rounded-image {
  border-radius: 999px;
}

.demo-avatar-status-wrap {
  position: relative;
}

.demo-avatar-status {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 999px;
  background: rgb(34 197 94);
  box-shadow: 0 0 0 2px var(--vp-c-bg);
}
</style>

Styling

Passing Classes

vue
<template>
  <Avatar class="size-20">
    <AvatarImage src="..." alt="..." />
    <AvatarFallback>XL</AvatarFallback>
  </Avatar>
</template>

CSS Classes

ClassDescription
.avatarBase avatar container
.avatar__imageImage element
.avatar__fallbackFallback content container
.avatar--smSmall size
.avatar--mdMedium size
.avatar--lgLarge size
.avatar--softSoft visual variant
.avatar__fallback--defaultDefault fallback color
.avatar__fallback--accentAccent fallback color
.avatar__fallback--successSuccess fallback color
.avatar__fallback--warningWarning fallback color
.avatar__fallback--dangerDanger fallback color

API

Avatar Props

PropTypeDefaultDescription
size'sm' | 'md' | 'lg''md'Avatar size
color'default' | 'accent' | 'success' | 'warning' | 'danger''default'Fallback color theme
variant'default' | 'soft''default'Visual style variant
classstringundefinedAdditional classes for the avatar root

AvatarImage Props

PropTypeDefaultDescription
srcstringundefinedImage source URL
srcsetstringundefinedResponsive image srcset
sizesstringundefinedResponsive image sizes
altstringundefinedAlternative text
crossorigin'anonymous' | 'use-credentials'undefinedCORS setting
loading'eager' | 'lazy'undefinedNative image loading strategy
classstringundefinedAdditional classes for the image

AvatarImage Events

EventPayloadDescription
loadEventEmitted when the image loads
errorEventEmitted when the image fails and fallback should show

AvatarFallback Props

PropTypeDefaultDescription
delayMsnumberundefinedDelay before rendering fallback content
color'default' | 'accent' | 'success' | 'warning' | 'danger'Parent colorOverride fallback color
classstringundefinedAdditional classes for the fallback

Slots

ComponentSlotDescription
AvatardefaultImage and fallback content
AvatarFallbackdefaultText, icon, or custom fallback content

Released under the Apache-2.0 License.