<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.
<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
Avatar.Root
├── Avatar.Image
├── Avatar.Fallback
└── Avatar.Badge
Avatar.Group
├── Avatar.Root
├── Avatar.Root
└── Avatar.GroupCountThe 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.
<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.
<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.
smdefaultlg<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.
<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.”
<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.
<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.
statusChangereports 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.
| Prop | Type | Default | Description |
|---|---|---|---|
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. |
asChild | boolean | false | Merges the root behavior and attributes onto its single child. |
id | string | generated | Sets the Ark UI machine identifier. |
ids | Partial<{ root: string; image: string; fallback: string }> | generated | Overrides the generated part identifiers for composition. |
| Event | Detail | Description |
|---|---|---|
@status-change | { status: "loaded" | "error" } | Reports image loading success or failure. It does not describe user presence. |
Parts
| Part | Element | Description |
|---|---|---|
Avatar.Image | img | Ark image part; forwards native image attributes and supports asChild. |
Avatar.Fallback | span | Visible while the image loads and after an error; supports asChild. |
Avatar.Badge | span | Attribute-transparent overlay slot for presence or another concise marker. |
Avatar.Group | div | Attribute-transparent overlapping collection; neutral until the consumer adds semantics. |
Avatar.GroupCount | div | Count surface with consumer-provided content and contextual accessible text. |
Exports
| Export | Description |
|---|---|
Avatar | Compound API exposing Root, Image, Fallback, Badge, Group, and GroupCount. |
AvatarRoot | Named root export with Ark image-status behavior. |
AvatarImage | Named image part export. |
AvatarFallback | Named fallback part export. |
AvatarBadge | Named badge overlay export. |
AvatarGroup | Named overlapping group export. |
AvatarGroupCount | Named additional-member count export. |
AVATAR_SIZES / AVATAR_DEFAULT_SIZE | Readonly supported sizes and the default-size constant. |
isAvatarSize / resolveAvatarSize | Runtime validation and default resolution for size input. |
AvatarProps / AvatarRootProps / AvatarEmits | Public root prop and event contracts. |
AvatarSlots / AvatarRootSlots | Root default-slot contracts. |
AvatarImageProps / AvatarImageSlots | Ark and native image prop and slot contracts. |
AvatarFallbackProps / AvatarFallbackSlots | Ark and native fallback prop and slot contracts. |
AvatarBadgeProps / AvatarBadgeSlots | Native badge attribute and slot contracts. |
AvatarGroupProps / AvatarGroupSlots | Native group attribute and slot contracts. |
AvatarGroupCountProps / AvatarGroupCountSlots | Native count attribute and slot contracts. |
AvatarStatusChangeDetails | Image load-result details: loaded or error. |
AvatarSize | Supported root-size union. |
AvatarDirection | Supported root-direction union. |