Skip to content

Avatar Component ​

<Avatar /> renders an accessible initials, image, or deterministic pixel-art avatar. Images fall back to the selected avatar variant if they fail to load.

Common usage ​

vue
<Avatar
  name="Tony Stark"
  image-src="/tony.jpg"
  status="online"
  :size="64"
  :auto-contrast="true"
/>

Props reference ​

PropTypeDefaultDescription
nameStringrequiredName used for initials and the accessible label; also seeds generated colours and pixel art when seed is omitted.
seedString | NumbernameStable identity for generated colours and pixel art. Initials and labels still use name.
imageSrcString—Image URL. In templates use image-src.
variant'initials' | 'pixel''initials'Selects initials or deterministic pixel art.
pixelThemeString'earth'Pixel theme: earth, neon, ocean, forest, sunset, midnight, candy, or retro.
sizeNumber40Avatar diameter in pixels.
inlineBooleanfalseDisplays the avatar inline.
shape'circle' | 'square' | 'squircle' | 'hexagon'derivedExplicit shape. Overrides rounded when set.
roundedBooleantrueLegacy circle/square switch when shape is not supplied.
color / backgroundStringgeneratedOverride the foreground or background colour.
darkBooleanfalseUses the dark generated palette.
gradientBooleanfalseUses a name-based background gradient.
autoContrastBooleanfalseUses black or white text for a hexadecimal background colour.
border / borderColorBoolean / Stringtrue / 'white'Controls the native image border; initials and pixel avatars keep their outline.
altStringderivedAccessible label. Defaults to Avatar of {name}.
loading'lazy' | 'eager''lazy'Native image loading behaviour.
transitionBooleantrueEnables the image fade-in transition.
interactiveBooleanfalseMakes the avatar keyboard-activatable and emits activate.
pointerBooleanfalseUses a pointer cursor without making the avatar interactive.
onClickFunction—Click callback; also makes the avatar keyboard-activatable.
customAvatarStyle / customStatusStyleObject{}Inline style overrides for the avatar or status indicator.
useLegacyColorsBooleanfalseUses the legacy vue-avatar colour palette.
useTextColorForBorderBooleanfalseUses the calculated text colour as the border colour.

Initials and Unicode names ​

Initials keep the existing first/second/last-word selection rule, while treating visible grapheme clusters as one character. This keeps emoji, flags, combining accents, and zero-width-joiner sequences intact instead of splitting their UTF-16 code units. Repeated whitespace is ignored, and hyphens remain word separators.

vue
<Avatar name="👩‍💻 Ada" />       <!-- 👩‍💻A -->
<Avatar name="éclair Smith" />  <!-- ÉS -->
<Avatar name="🇩🇪 Berlin" />      <!-- 🇩🇪B -->

The component uses Intl.Segmenter when available and a bundled fallback for common combining marks, emoji modifiers, flags, and joined emoji. The same algorithm runs during SSR and hydration, so the visible initials and font size remain stable across supported environments.

Stable generated avatars ​

Pass a stable user ID as seed to keep generated colours and pixel art consistent when the display name changes. Initials, the default tooltip, and the accessible label continue to use name.

vue
<Avatar :name="user.displayName" :seed="user.id" />
<Avatar :name="user.displayName" :seed="user.id" variant="pixel" />

Try entering a seed in the playground, then changing the name. Omit seed to retain the existing name-based output. Numeric seeds are converted to strings (42 and "42" produce the same output); 0 and "" are valid explicit seeds. Supply the same seed on the server and client for consistent rendering. The existing generators can produce collisions, so different seeds do not guarantee different artwork or colours. Explicit colour overrides and pixel themes continue to apply, and image loading/fallback behavior is unchanged.

Images ​

PropTypeDefaultDescription
fallbackSrcString | String[]—Sources tried in order when imageSrc fails, before falling back to initials or pixel art.
skeletonBooleantrueShows a shimmer placeholder while the image loads. Rendered only after mount, so server output and the first client render agree.
retinaBooleanfalseDerives an @2x srcset from imageSrc when no explicit srcset is set.
srcset / sizesString—Passed straight through to the <img>. An explicit srcset wins over retina.
crossorigin'anonymous' | 'use-credentials'—Passed through to the <img>.
referrerpolicyString—Passed through to the <img>.
decoding'async' | 'sync' | 'auto''async'Passed through to the <img>.

Changing imageSrc resets the whole chain, so an avatar that failed once retries as soon as it is given a new source.

vue
<Avatar
  name="Tony Stark"
  image-src="https://cdn.example.com/tony.jpg"
  :fallback-src="['https://backup.example.com/tony.jpg', '/default.png']"
  retina
  @fallback="({ failedSrc, remaining }) => console.warn(failedSrc, remaining)"
/>

Status ​

PropTypeDefaultDescription
statusString—online, away, offline, busy, or any key present in statusColors.
statusPositionString'bottom-right'top-right, top-left, bottom-right, or bottom-left.
statusColorString—Overrides the colour for this avatar, whatever the status is.
statusColorsObject{}Extra or replacement colours, merged over the built-in four. Also accepted in the global config.
statusSize'sm' | 'md' | 'lg' | Number'md'Dot size, as a fraction of the avatar (sm = 1/5, md = 1/4, lg = 1/3) or explicit pixels.
statusLabelString—Replaces "User is {status}" in the accessible label.
statusPulseBooleanfalseAnimates a pulsing ring. Suppressed under prefers-reduced-motion.
sameBorderBooleanfalseMakes the status indicator use the avatar border colour.

The indicator is inset to sit on the avatar's outline rather than in the empty corner of its bounding box, by an amount that depends on shape — squares get no inset, hexagons the most.

vue
<Avatar
  name="Tony Stark"
  status="in-meeting"
  status-label="In a meeting until 4pm"
  :status-colors="{ 'in-meeting': '#7c3aed' }"
  status-size="lg"
  status-pulse
/>

Badge ​

PropTypeDefaultDescription
badgeString | Number—Badge content. Renders the badge when set.
badgeVariant'count' | 'dot' | 'icon''count'dot renders an empty marker and needs no badge value.
badgeMaxNumber999Counts above this render as {max}+. Digit strings are clamped the same way as numbers.
badgeMaxLengthNumber3Letters kept in a non-numeric badge. "Promotional" renders as "Pro".
badgePositionString'top-right'Same four corners as statusPosition. A development warning fires if the two collide.
badgeColor / badgeTextColorString'#ef4444' / derivedBackground and text colour. Given only a hexadecimal background, the text colour is chosen for contrast.
badgeLabelStringderivedWording for the badge in the accessible label.
customBadgeStyleObject{}Inline style overrides for the badge.

The badge is aria-hidden; its meaning is folded into the avatar's aria-label so screen readers announce it once rather than twice.

Badge content is capped so a corner marker stays a corner marker: counts above badgeMax become 999+, and other content is trimmed to badgeMaxLength letters — the same three-character budget the initials use. A label badge is anchored to a corner and grows towards the middle, so without a cap a long string runs across the face and out the far side.

vue
<Avatar name="Tony Stark" :badge="1200" />          <!-- 999+ -->
<Avatar name="Tony Stark" badge="Promotional" />    <!-- Pro  -->

The badge sits further out from the corner than the status dot, and is allowed to overhang the avatar's edge: a round dot reads best tucked onto the outline, whereas a wide pill pulled in by the same amount drifts towards the middle of the face.

The badge is also capped at the avatar's own width, with a CSS ellipsis as a backstop for wide glyphs. To allow a longer or wider badge:

vue
<Avatar
  name="Tony Stark"
  badge="Promotional"
  :badge-max-length="6"
  :custom-badge-style="{ maxWidth: '180px' }"
/>

Tooltip ​

See the Tooltip page for the full reference.

PropTypeDefaultDescription
tooltipString | Boolean | Object—Tooltip content. Unset uses name; false disables it; an object supplies inline overrides.
nativeTitleBooleanfalseRestores the v4 title attribute instead of the styled tooltip.

Interaction ​

PropTypeDefaultDescription
as'div' | 'button' | 'a''div'Root element. button and a bring real semantics and native keyboard handling.
href / target / relString—Used when as="a". target="_blank" adds rel="noopener noreferrer" unless rel is set.
disabledBooleanfalseBlocks activation, dims the avatar, and sets aria-disabled (or the native disabled attribute on a button).
selectedBoolean—Opt-in toggle state, rendered as aria-pressed. Leave unset for avatars that are not toggles.
editableBooleanfalseAdds an overlay for changing the picture. Emits edit. On a div root the overlay is its own button; with as="button" or as="a" it is decoration and the root's own activation emits edit, because a button cannot be nested inside a button or a link.
acceptString—With editable, wires a hidden file input and emits file-select.
editLabelString'Change picture'Accessible label for the edit overlay.
vue
<Avatar
  name="Tony Stark"
  as="a"
  href="/users/tony"
  target="_blank"
  image-src="/tony.jpg"
/>

<Avatar
  name="Tony Stark"
  editable
  accept="image/*"
  @file-select="({ files }) => upload(files[0])"
/>

Events ​

EventPayloadWhen it fires
@errorEventThe image fails to load.
@loadEventThe image loads.
@activateEventAn interactive avatar is clicked or activated with Enter/Space.
@fallback{ failedSrc, nextSrc, remaining, event }An image fails and another source remains to try. @error fires only once the chain is exhausted.
@editMouseEventThe edit overlay is activated.
@file-select{ files, event }A file is chosen through the accept file input.

Slots ​

SlotScopeDescription
image{ src, srcset, sizes, alt, size, style, class, onLoad, onError }Replace the native image, for example with NuxtImg. Bind the supplied callbacks so loading and fallback state stays synchronized. src is the current link in the fallback chain.
placeholder{ size, style }Render a placeholder when neither name nor image-src is present.
status—Replace the visual content of the status indicator.
badge—Replace the visual content of the badge.
overlay—Add content positioned within the avatar container.
tooltip{ nameValue, initials, status, imageSrc }Replace the tooltip body with a rich hover card.
edit-overlay—Replace the camera icon on the edit overlay.

Nuxt image slot ​

vue
<Avatar name="Tony Stark" image-src="/tony.jpg">
  <template #image="{ src, srcset, sizes, alt, size, style, class: imageClass, onLoad, onError }">
    <NuxtImg
      :src="src"
      :srcset="srcset"
      :sizes="sizes"
      :alt="alt"
      :width="size"
      :height="size"
      :style="style"
      :class="imageClass"
      @load="onLoad"
      @error="onError"
    />
  </template>
</Avatar>

The callbacks belong to the current source attempt. Bind them to the rendered image even when using a framework image component; an old image finishing after the URL changes is ignored. A changed fallback chain starts over from the primary source, while an equivalent chain keeps a loaded image in place.

CSS variables ​

The root element exposes the avatar's resolved values so surrounding styles can follow along: --va-size, --va-bg, --va-color, --va-border-color, --va-radius, --va-clip-path, --va-font-size, --va-status-color, --va-status-size, --va-badge-bg, and --va-badge-color.

These are read by the component and can be set by you: --va-focus-ring (focus outline colour), --va-ring-color (selected ring), --va-skeleton-bg, --va-skeleton-shimmer, --va-edit-overlay-bg, and --va-edit-overlay-color.

Released under the MIT License.