Skip to main content
Search
Search the documentation

Avatar

A person's image with an initials fallback, wired in one line.

pnpm dlx shadcn-svelte@latest add https://coral.imlargo.dev/r/kit-avatar.json

Raw shadcn asks for three components and a hand-written fallback every single time:

<Avatar>
	<AvatarImage src={user.photo} alt={user.name} />
	<AvatarFallback>{user.name.slice(0, 2).toUpperCase()}</AvatarFallback>
</Avatar>

That last line is the problem. It is rewritten in every project, and it is wrong in most of them: slice(0, 2) on Elena van der Meer gives EL, not EM.

Shad CN
Elena van der Meer
Kenji

What Coral adds

  • Correct initials, not slice(0, 2). First letter of the first word, plus first letter of the last one: "Elena van der Meer" gives EM, not EL.
  • One accessible label, never doubled. The image's alt and the fallback's hidden label are the same text, and only one of the two is ever in the accessibility tree at a time.
  • An empty state without a placeholder nobody asked for. No name and no fallback is an empty circle, not text made up to fill it.
  • The pieces stay reachable. children renders alongside the image, and AvatarGroup still wraps a Coral avatar unchanged.

Import

<script lang="ts">
	import Avatar from '#lib/components/coral/kit/avatar/avatar.svelte';
</script>

Props

Everything the shadcn root accepts stays available: size, class, delayMs, loadingStatus, ref and any div attribute. On top of that:

PropTypeDefaultDescription
srcstring-Image URL. Absent or failed to load, the fallback shows instead.
altstringnameAlt text for the image. Falls back to '', i.e. decorative.
namestring-Person's name. Derives the initials and acts as the default alt.
fallbackstring | Snippet-Replaces the derived initials. Text, or a snippet for full control.
childrenSnippet-Extra content inside the root, alongside the image - e.g. a badge.

Fallback

The fallback is shown when there is no src, and when the image fails to load. Initials come from name: first letter of the first word, plus first letter of the last word when there is more than one. Single-word names give a single letter.

An empty or missing name produces an empty string rather than a placeholder. The caller decides what an unknown person looks like, and gets an empty circle until it says so.

Amara Diallo
Amara Diallo
Amara Diallo

Accessibility

An avatar is called the same thing whether or not the photo loads. name becomes the image's alt, and (when the fallback is showing instead) a visually hidden label, so a screen reader reads Elena van der Meer rather than the letters E M.

Only one of the two is ever in the accessibility tree: the fallback is display: none while the image is showing, so the name is never announced twice.

GivenA screen reader readsOn screen
namethe nameinitials
name + a broken srcthe nameinitials
name + a working srcthe name (via alt)the photo
name + alt=""nothinginitials
fallback with no namethe fallback textthat text
nothingnothingempty

alt="" means here what it means everywhere else: this avatar is decorative, the name is already in the text next to it. Use it in a table row or a list item that already names the person, and the same name will not be read twice.

Sizes

size is forwarded straight to the shadcn root. Coral adds nothing here, and removes nothing.

Shad CN
Shad CN
Shad CN
Amara Diallo
Amara Diallo
Amara Diallo

Custom fallback

When initials are not the right answer (an unauthenticated user, a machine account), pass a snippet instead of a string.

Escaping the flat API

The pieces stay reachable. children renders inside the root, next to the image, so anything the primitive supports still works without dropping Coral.

Shad CN
Amara Diallo

The same goes for grouping: AvatarGroup comes from shadcn and Coral avatars sit inside it unchanged.

Amara Diallo
Wei Zhang
Sofia Rossi
Liam O'Connor
+3

Why flat props

Avatar has a defensible canonical case: a person, maybe a photo, initials when there is no photo. The parts do not vary independently, so composition would be ceremony. This is the shape the conventions call for: flat props, and the pieces still reachable when the rare case shows up.

initials()

The derivation lives in kit/avatar/initials.ts and is exported on its own, so a project that needs the same initials somewhere else (a mention chip, an export, a PDF) does not re-implement it.

import { initials } from '#lib/components/coral/kit/avatar/initials.js';

initials('Elena van der Meer'); // 'EM'
initials('Kenji'); // 'K'
initials('   '); // ''
initials(undefined); // ''

It stays inside the component's folder rather than in lib/ because it has exactly one consumer in Coral today. It moves the day a second component needs it.