c2-avatar shows a person or entity. It resolves its content in order: the src image (a broken image fires error and falls back to the initials), then slotted content such as an icon or emoji, then the initials computed from name. initial-count="2" picks the first and last word of a longer name, and initials overrides the computation. auto-color derives a stable background hue from the name, status adds a presence dot, and the badge slot replaces the dot with your own element. One --c2-avatar--size token drives the width, height and font size. The same package also exports c2-avatar-group, which stacks avatars responsively and replaces those that no longer fit with an automatic count.
Import
import '@c2n/components/avatar'
Usage
Importimport '@c2n/components/avatar'
Markup<style>
.responsive-group {
--c2-avatar-group--max-width: 150px;
}
.responsive-group c2-avatar {
--c2-avatar--size: 36px;
}
.badge {
background: #dc2626;
color: #ffffff;
font-size: 10px;
font-weight: 700;
line-height: 1;
padding: 2px 5px;
}
.editable-avatar {
--c2-avatar--size: 72px;
}
</style>
<div data-label="Initials">
<c2-avatar name="Nguyen Thai Vinh"></c2-avatar>
<c2-avatar name="Nguyen Thai Vinh" initial-count="2"></c2-avatar>
<c2-avatar name="Nguyen Thai Vinh" initials="TV"></c2-avatar>
</div>
<div data-label="Sizes">
<c2-avatar name="Ada Lovelace" initial-count="2" style="--c2-avatar--size: 20px"></c2-avatar>
<c2-avatar name="Ada Lovelace" initial-count="2"></c2-avatar>
<c2-avatar name="Ada Lovelace" initial-count="2" style="--c2-avatar--size: 48px"></c2-avatar>
<c2-avatar name="Ada Lovelace" initial-count="2" style="--c2-avatar--size: 64px"></c2-avatar>
</div>
<div data-label="Image and fallbacks">
<c2-avatar name="Elisa Jasmin" src="/web-components/chat.avif" style="--c2-avatar--size: 48px"></c2-avatar>
<c2-avatar name="Elisa Jasmin" initial-count="2" src="/web-components/missing.png" style="--c2-avatar--size: 48px"></c2-avatar>
<c2-avatar name="Assistant" style="--c2-avatar--size: 48px; --c2-avatar--background: #18181b">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="8" width="18" height="12" rx="2"></rect><path d="M12 8V4M8 14h.01M16 14h.01"></path></svg>
</c2-avatar>
</div>
<div data-label="Auto color">
<c2-avatar auto-color name="Ada Lovelace" initial-count="2"></c2-avatar>
<c2-avatar auto-color name="Grace Hopper" initial-count="2"></c2-avatar>
<c2-avatar auto-color name="Alan Turing" initial-count="2"></c2-avatar>
<c2-avatar auto-color name="Katherine Johnson" initial-count="2"></c2-avatar>
<c2-avatar auto-color name="Linus Torvalds" initial-count="2"></c2-avatar>
</div>
<div data-label="Status and badge">
<c2-avatar name="Ada Lovelace" initial-count="2" status="online"></c2-avatar>
<c2-avatar name="Ada Lovelace" initial-count="2" status="away"></c2-avatar>
<c2-avatar name="Ada Lovelace" initial-count="2" status="busy"></c2-avatar>
<c2-avatar name="Ada Lovelace" initial-count="2" status="offline"></c2-avatar>
<c2-avatar name="Ada Lovelace" initial-count="2" style="--c2-avatar--size: 40px"><span slot="badge" class="badge">3</span></c2-avatar>
</div>
<div data-label="Editable">
<c2-avatar class="editable-avatar" editable name="Elisa Jasmin" src="/web-components/chat.avif"></c2-avatar>
<c2-avatar class="editable-avatar" editable auto-color name="Ada Lovelace" initial-count="2"></c2-avatar>
</div>
<div data-label="Responsive group">
<c2-avatar-group class="responsive-group" aria-label="Project contributors" client:only="lit">
<c2-avatar auto-color name="Ada Lovelace" initial-count="2"></c2-avatar>
<c2-avatar auto-color name="Grace Hopper" initial-count="2"></c2-avatar>
<c2-avatar auto-color name="Alan Turing" initial-count="2"></c2-avatar>
<c2-avatar auto-color name="Katherine Johnson" initial-count="2"></c2-avatar>
<c2-avatar auto-color name="Margaret Hamilton" initial-count="2"></c2-avatar>
<c2-avatar auto-color name="Radia Perlman" initial-count="2"></c2-avatar>
</c2-avatar-group>
</div>
<div data-label="Total count">
<c2-avatar-group class="responsive-group" count-mode="total" max-visible="3" aria-label="Design team" client:only="lit">
<c2-avatar auto-color name="Dieter Rams" initial-count="2"></c2-avatar>
<c2-avatar auto-color name="Susan Kare" initial-count="2"></c2-avatar>
<c2-avatar auto-color name="Paula Scher" initial-count="2"></c2-avatar>
<c2-avatar auto-color name="Don Norman" initial-count="2"></c2-avatar>
<c2-avatar auto-color name="Irene Au" initial-count="2"></c2-avatar>
</c2-avatar-group>
</div>
Add editable when the person should be able to choose, replace, or remove their own avatar. Clicking the avatar opens an image picker and immediately previews the local file. Existing images receive a separate remove action; removing one restores initials or slotted fallback content. Use accept and max-size to constrain the file before your application uploads it.
const avatar = document.querySelector('c2-avatar')
avatar.addEventListener('avatar-change', async event => {
const remoteUrl = await uploadAvatar(event.detail.file)
avatar.src = remoteUrl
})
avatar.addEventListener('avatar-remove', () => {
deleteAvatar()
})
The component owns selection and the local preview, not network transport. avatar-change provides the selected File; avatar-remove identifies the previous source. Invalid files emit file-reject. Call browse() or removeImage() when external controls need to trigger the same actions, and customize their graphics with the edit-icon and remove-icon slots.
c2-avatar-group never marks the avatars it hides with an attribute, so the markup your page rendered stays exactly as written. A hidden avatar matches the custom state c2-avatar:state(group-hidden) instead (earlier releases wrote a data-c2-avatar-group-hidden attribute on it), and the group’s visible, hiddenCount and overflow-change report the counts.