Skip to content
Kappa
Avatar
@dicehub/kappav0.4.2

Avatar

Represents a person or entity with a portrait, resilient fallback, status marker, and compact group composition.

Mei ChenLead simulation engineer · Online
Case reviewWind tunnel · Run 042
Review team
Lina Haddad
Samir Aziz
3 additional reviewers
<script setup>
import { Avatar } from "@dicehub/kappa/components/avatar";

const reviewers = [
  { name: "Lina Haddad", image: "/avatars/lina-haddad.webp", initials: "LH" },
  { name: "Samir Aziz", image: "/avatars/samir-aziz.webp", initials: "SA" },
];
</script>

<template>
  <article class="profile-card">
    <header>
      <Avatar.Root size="lg">
        <Avatar.Image src="/avatars/mei-chen.webp" alt="" />
        <Avatar.Fallback aria-hidden="true">MC</Avatar.Fallback>
        <Avatar.Badge role="img" aria-label="Online">
          <svg viewBox="0 0 12 12" aria-hidden="true"><path d="m3 6 2 2 4-4" /></svg>
        </Avatar.Badge>
      </Avatar.Root>
      <div><strong>Mei Chen</strong><span>Lead simulation engineer · Online</span></div>
    </header>

    <footer>
      <span id="review-team">Review team</span>
      <Avatar.Group role="group" aria-labelledby="review-team">
        <Avatar.Root v-for="reviewer in reviewers" :key="reviewer.name" size="sm">
          <Avatar.Image :src="reviewer.image" :alt="reviewer.name" />
          <Avatar.Fallback>
            <span aria-hidden="true">{{ reviewer.initials }}</span>
            <span class="visually-hidden">{{ reviewer.name }}</span>
          </Avatar.Fallback>
        </Avatar.Root>
        <Avatar.GroupCount>
          <span aria-hidden="true">+3</span>
          <span class="visually-hidden">3 additional reviewers</span>
        </Avatar.GroupCount>
      </Avatar.Group>
    </footer>
  </article>
</template>

Installation

Barrel

import {
  Avatar,
  AvatarRoot,
  AvatarImage,
  AvatarFallback,
  AvatarBadge,
  AvatarGroup,
  AvatarGroupCount,
} from "@dicehub/kappa";

Granular

import {
  Avatar,
  AvatarRoot,
  AvatarImage,
  AvatarFallback,
  AvatarBadge,
  AvatarGroup,
  AvatarGroupCount,
} from "@dicehub/kappa/components/avatar";

Usage

Compose Image and Fallback inside Root. The fallback is rendered during loading and after an image error, so it should communicate the same identity as the image.

Mei Chen
<script setup>
import { Avatar } from "@dicehub/kappa/components/avatar";
</script>

<template>
  <Avatar.Root>
    <Avatar.Image src="/avatars/mei-chen.webp" alt="Mei Chen" />
    <Avatar.Fallback>
      <span aria-hidden="true">MC</span>
      <span class="visually-hidden">Mei Chen</span>
    </Avatar.Fallback>
  </Avatar.Root>
</template>

Composition

Typical part hierarchy
Avatar.Root
├── Avatar.Image
├── Avatar.Fallback
└── Avatar.Badge

Avatar.Group
├── Avatar.Root
├── Avatar.Root
└── Avatar.GroupCount

The compound API and named exports are equivalent. Badge, Group, and GroupCount are attribute-transparent Kappa parts aroundArk UI Avatar, which owns the image-loading behavior and accessibility state.

Lina Haddad
<script setup>
import {
  AvatarRoot,
  AvatarImage,
  AvatarFallback,
  AvatarBadge,
} from "@dicehub/kappa/components/avatar";
</script>

<template>
  <AvatarRoot>
    <AvatarImage src="/avatars/lina-haddad.webp" alt="Lina Haddad" />
    <AvatarFallback>
      <span aria-hidden="true">LH</span>
      <span class="visually-hidden">Lina Haddad</span>
    </AvatarFallback>
    <AvatarBadge aria-hidden="true">
      <svg viewBox="0 0 12 12" aria-hidden="true"><path d="m3 6 2 2 4-4" /></svg>
    </AvatarBadge>
  </AvatarRoot>
</template>

Examples

Image and Fallback

Ark UI keeps Fallback visible while Image loads and whenever loading fails. ThestatusChange detail is loaded or error; it reports image state, not a person's online presence.

Mei Chen
Image event: waiting for image eventFallback remains visible while loading and after an error.
<script setup>
import { ref } from "vue";
import { Avatar } from "@dicehub/kappa/components/avatar";

const source = ref("/avatars/missing.svg");
const imageStatus = ref("waiting for image event");

function handleStatusChange(details) {
  imageStatus.value = details.status;
}
</script>

<template>
  <Avatar.Root size="lg" @status-change="handleStatusChange">
    <Avatar.Image :src="source" alt="Mei Chen" />
    <Avatar.Fallback>
      <span aria-hidden="true">MC</span>
      <span class="visually-hidden">Mei Chen</span>
    </Avatar.Fallback>
  </Avatar.Root>
  <p>Image event: {{ imageStatus }}</p>
  <button type="button" @click="source = '/avatars/mei-chen.webp'">Load portrait</button>
</template>

Sizes

Use sm for dense lists and groups, the default size for most identity rows, and lg where identity leads the composition.

sm
default
lg
<script setup>
import { Avatar } from "@dicehub/kappa/components/avatar";
</script>

<template>
  <div role="group" aria-label="Yuki Tanaka avatar sizes">
    <Avatar.Root v-for="size in ['sm', 'default', 'lg']" :key="size" :size="size">
      <Avatar.Image src="/avatars/yuki-tanaka.webp" alt="" />
      <Avatar.Fallback aria-hidden="true">YT</Avatar.Fallback>
    </Avatar.Root>
  </div>
</template>

Status Badge

Badge provides placement only. Give a meaningful marker a role and accessible name, then repeat essential status in text so meaning never relies on color alone. Do not add a live region unless the application needs to announce a change.

Samir AzizOnline
<script setup>
import { Avatar } from "@dicehub/kappa/components/avatar";
</script>

<template>
  <div class="member">
    <Avatar.Root>
      <Avatar.Image src="/avatars/samir-aziz.webp" alt="" />
      <Avatar.Fallback aria-hidden="true">SA</Avatar.Fallback>
      <Avatar.Badge class="online" role="img" aria-label="Online">
        <svg viewBox="0 0 12 12" aria-hidden="true"><path d="m3 6 2 2 4-4" /></svg>
      </Avatar.Badge>
    </Avatar.Root>
    <div><strong>Samir Aziz</strong><span>Online</span></div>
  </div>
</template>

Avatar Group

Group controls overlap but adds no semantics. Connect it to visible context withrole="group" and aria-labelledby when the collection is meaningful. GroupCount displays consumer-provided content; include contextual accessible text such as “3 more reviewers.”

Review team
Mei Chen
Lina Haddad
Samir Aziz
3 additional reviewers
<script setup>
import { Avatar } from "@dicehub/kappa/components/avatar";

const reviewers = [
  { name: "Mei Chen", image: "/avatars/mei-chen.webp", initials: "MC" },
  { name: "Lina Haddad", image: "/avatars/lina-haddad.webp", initials: "LH" },
  { name: "Samir Aziz", image: "/avatars/samir-aziz.webp", initials: "SA" },
];
</script>

<template>
  <span id="review-team">Review team</span>
  <Avatar.Group role="group" aria-labelledby="review-team">
    <Avatar.Root v-for="reviewer in reviewers" :key="reviewer.name" size="sm">
      <Avatar.Image :src="reviewer.image" :alt="reviewer.name" />
      <Avatar.Fallback>
        <span aria-hidden="true">{{ reviewer.initials }}</span>
        <span class="visually-hidden">{{ reviewer.name }}</span>
      </Avatar.Fallback>
    </Avatar.Root>
    <Avatar.GroupCount>
      <span aria-hidden="true">+3</span>
      <span class="visually-hidden">3 additional reviewers</span>
    </Avatar.GroupCount>
  </Avatar.Group>
</template>

Account Menu Trigger

Avatar is non-interactive. Place it inside a semantic button when it opens a menu and label that button with the action and identity. An empty image alt and hidden fallback avoid repeating a name already supplied by the button label.

Account options
<script setup>
import { Menu } from "@ark-ui/vue/menu";
import { Avatar } from "@dicehub/kappa/components/avatar";
</script>

<template>
  <span id="account-options" class="visually-hidden">Account options</span>
  <Menu.Root>
    <Menu.Trigger as-child>
      <button type="button" aria-label="Open account menu for Lina Haddad">
        <Avatar.Root size="sm">
          <Avatar.Image src="/avatars/lina-haddad.webp" alt="" />
          <Avatar.Fallback aria-hidden="true">LH</Avatar.Fallback>
        </Avatar.Root>
        <span>Lina Haddad</span>
      </button>
    </Menu.Trigger>
    <Menu.Positioner>
      <Menu.Content aria-labelledby="account-options">
        <Menu.Item value="profile">Profile</Menu.Item>
        <Menu.Item value="sign-out">Sign out</Menu.Item>
      </Menu.Content>
    </Menu.Positioner>
  </Menu.Root>
</template>

Right-to-left

Set dir="rtl" on each Root so Ark UI applies direction to Image and Fallback. Group and Badge use logical positioning and preserve the expected overlap order.

فريق المراجعة
لينا حداد
سمير عزيز
مراجعان إضافيان
<script setup>
import { Avatar } from "@dicehub/kappa/components/avatar";
</script>

<template>
  <Avatar.Group dir="rtl" role="group" aria-labelledby="rtl-review-team">
    <span id="rtl-review-team" class="visually-hidden">فريق المراجعة</span>
    <Avatar.Root dir="rtl">
      <Avatar.Image src="/avatars/lina-haddad.webp" alt="لينا حداد" />
      <Avatar.Fallback>
        <span aria-hidden="true">لح</span>
        <span class="visually-hidden">لينا حداد</span>
      </Avatar.Fallback>
      <Avatar.Badge aria-hidden="true">
        <svg viewBox="0 0 12 12" aria-hidden="true"><path d="m3 6 2 2 4-4" /></svg>
      </Avatar.Badge>
    </Avatar.Root>
    <Avatar.Root dir="rtl">
      <Avatar.Image src="/avatars/samir-aziz.webp" alt="سمير عزيز" />
      <Avatar.Fallback>
        <span aria-hidden="true">سع</span>
        <span class="visually-hidden">سمير عزيز</span>
      </Avatar.Fallback>
    </Avatar.Root>
    <Avatar.GroupCount>
      <span aria-hidden="true">+٢</span>
      <span class="visually-hidden">مراجعان إضافيان</span>
    </Avatar.GroupCount>
  </Avatar.Group>
</template>

Accessibility

  • For a standalone identity, give Image meaningful alt text and make Fallback communicate the same person or entity.
  • When adjacent text or a labelled control already names the identity, use alt="" and hide redundant fallback text from assistive technology.
  • Never omit alt. A missing image description and an intentionally decorative image are different states.
  • Fallback appears while loading as well as after an error. Keep it stable during server rendering and hydration.
  • statusChange reports image loading only. Presence needs separate application data and visible or programmatic text.
  • Badge has no implicit role or live-region behavior. Do not rely on color alone for status.
  • Group is neutral. Add collection semantics only when they help, and connect them to visible or visually hidden context.
  • GroupCount is not calculated. Render the correct count and include what it counts as real visible or visually hidden text.
  • Wrap Avatar in a labelled native link or button for navigation and actions; Avatar itself is not a trigger.

Kappa preserves Ark UI image-loading behavior. See theofficial Ark UI Avatar documentationfor the primitive contract.

API Reference

Avatar.Root

Renders the Ark UI root and forwards remaining attributes and listeners.

PropTypeDefaultDescription
size"sm" | "default" | "lg""default"Sets the avatar diameter and the scale of its composed parts.
dir"ltr" | "rtl"inherited Ark locale (ltr by default)Sets Ark UI direction for the root, image, and fallback.
asChildbooleanfalseMerges the root behavior and attributes onto its single child.
idstringgeneratedSets the Ark UI machine identifier.
idsPartial<{ root: string; image: string; fallback: string }>generatedOverrides the generated part identifiers for composition.
EventDetailDescription
@status-change{ status: "loaded" | "error" }Reports image loading success or failure. It does not describe user presence.

Parts

PartElementDescription
Avatar.ImageimgArk image part; forwards native image attributes and supports asChild.
Avatar.FallbackspanVisible while the image loads and after an error; supports asChild.
Avatar.BadgespanAttribute-transparent overlay slot for presence or another concise marker.
Avatar.GroupdivAttribute-transparent overlapping collection; neutral until the consumer adds semantics.
Avatar.GroupCountdivCount surface with consumer-provided content and contextual accessible text.

Exports

ExportDescription
AvatarCompound API exposing Root, Image, Fallback, Badge, Group, and GroupCount.
AvatarRootNamed root export with Ark image-status behavior.
AvatarImageNamed image part export.
AvatarFallbackNamed fallback part export.
AvatarBadgeNamed badge overlay export.
AvatarGroupNamed overlapping group export.
AvatarGroupCountNamed additional-member count export.
AVATAR_SIZES / AVATAR_DEFAULT_SIZEReadonly supported sizes and the default-size constant.
isAvatarSize / resolveAvatarSizeRuntime validation and default resolution for size input.
AvatarProps / AvatarRootProps / AvatarEmitsPublic root prop and event contracts.
AvatarSlots / AvatarRootSlotsRoot default-slot contracts.
AvatarImageProps / AvatarImageSlotsArk and native image prop and slot contracts.
AvatarFallbackProps / AvatarFallbackSlotsArk and native fallback prop and slot contracts.
AvatarBadgeProps / AvatarBadgeSlotsNative badge attribute and slot contracts.
AvatarGroupProps / AvatarGroupSlotsNative group attribute and slot contracts.
AvatarGroupCountProps / AvatarGroupCountSlotsNative count attribute and slot contracts.
AvatarStatusChangeDetailsImage load-result details: loaded or error.
AvatarSizeSupported root-size union.
AvatarDirectionSupported root-direction union.