Components

Avatar

Displays a user's profile image inside a circle, gracefully falling back to initials or an icon when the image is missing or fails to load.

Basic usage

Compose an Avatar from an AvatarImage and an AvatarFallback. Radix shows the image once it loads and the fallback otherwise.

AL

Image & fallback

The fallback is automatic — when AvatarImage is absent or its src fails to load, the initials render in its place on bg-muted. Recolour it with a role token pair such as bg-accent text-accent-foreground, never a raw scale step.

GHATCB

Sizes

The avatar is size-8 by default. Override it with any Tailwind size-* utility — the image and fallback scale to fill the circle.

SMMDLGXL

Letter avatar

LetterAvatar is the one you reach for in lists: give it a name and it renders the photo if there is one, otherwise Vietnamese-style initials (first letter of the family name plus first letter of the given name) on a tone derived from that name. It deliberately avoids the Radix primitive — no image-loading state means no client island, so 200 rows render straight on the server.

Nguyễn Thanh HàTrần Minh QuânLê Bảo ChâuPhạm Gia HuyĐỗ Khánh LinhGrace HopperComitor Tasks

Deterministic tones

The tone is a pure function of the name, so the same person is the same colour in every Comitor app — and the same colour again in canvas, e-mail, and PDF output, because getAvatarToneColors(name, mode) from @comitor/ui/tokens reads the same tone table. Use getAvatarToneClasses(name) when you need those classes on your own element; do not rebuild the hash, that is the shortest path to one person having two colours.

Vũ Hoàng NamComitor CRMVN

Avatar group

AvatarGroup stacks members and collapses the rest into a “+k” chip. Every face is a focusable button carrying a tooltip with the full name and an optional caption — overlapping avatars hide part of the initials, so without the tooltip the stack is decoration. Pass label and overflowLabel explicitly: the group's default aria-label is the Vietnamese “Thành viên”, and the “+k” button's own sr-only name is Vietnamese too.

Group surface

Tones are alpha tints, and the group intentionally overlaps them. Without an opaque layer beneath, the tint of the upper avatar composites with the colour of the one below instead of with the page. surfaceClassName supplies both that layer and the separating ring, and defaults to bg-card ring-card. Standing the group on another surface means restating both halves.

+2

Props

Avatar

PropTypeDefaultDescription
classNamestringTailwind classes merged onto the root (size-8 rounded-full overflow-hidden). Override size with size-* and the shape stays a circle.
...restAvatarPrimitive.Root propsAll Radix Avatar Root props are forwarded to the wrapper element, which carries data-slot="avatar".

AvatarImage

PropTypeDefaultDescription
srcrequiredstringURL of the image to display.
altrequiredstringAlternative text describing the person; required for screen readers.
onLoadingStatusChange(status: 'idle' | 'loading' | 'loaded' | 'error') => voidFires as the image moves through its loading lifecycle.
classNamestringMerged onto the img, which is aspect-square size-full by default.

AvatarFallback

PropTypeDefaultDescription
delayMsnumberWait this many milliseconds before rendering the fallback, avoiding a flash while a fast image loads. Renders immediately when omitted.
childrenrequiredReact.ReactNodeContent shown when the image is absent or fails — typically initials or an icon.
classNamestringMerged onto the fallback, which fills the circle on bg-muted by default.

LetterAvatar

PropTypeDefaultDescription
namerequiredstringFull name — drives both the initials and the tone. Also rendered into an sr-only span so the avatar is never a mute coloured square.
srcstring | nullPhoto URL. When present the image is shown instead of the initials, and the tone class is dropped.
size'xs' | 'sm' | 'md' | 'lg' | 'xl''md'One of five fixed sizes: 24, 28, 36, 44, and 56 px, each with a matching type scale.
squarebooleanfalseRounded square instead of a circle — the house convention for a workspace or an app, not a person.
toneClassNamestringOverrides the name-derived tone with your own token classes. Use it for a deliberate meaning (an app accent), never to re-roll the colour of a person.
...restReact.ComponentProps<'span'>All native span attributes are forwarded; children are not accepted.

AvatarGroup

PropTypeDefaultDescription
itemsrequiredAvatarGroupItem[]Members to show: { id, name, src?, caption? }. caption becomes the tooltip’s second line — an email or a role.
maxnumber4How many avatars render before the rest collapse into the "+k" chip.
size'xs' | 'sm' | 'md' | 'lg' | 'xl''sm'Passed through to each LetterAvatar. The overlap scales with it — roughly 20% at every size, so the initials stay readable.
onOverflowClick() => voidMakes the "+k" chip a button — typically opens the full member list. Without it the chip renders as static text.
overflowLabel(count: number) => string(count) => `Xem tất cả ${count} thành viên`sr-only name of the "+k" button when onOverflowClick makes it clickable. A function, not a template string, and it receives items.length — the whole group, not the hidden remainder. Vietnamese by default: translating only label leaves this button speaking Vietnamese.
labelstring'Thành viên'aria-label for the group. The package default is Vietnamese — pass an English string in an English UI.
surfaceClassNamestring'bg-card ring-card'Background plus ring colour of the surface the group sits on. Both halves must be restated together when the group is not on a card.
classNamestringMerged onto the group wrapper, which carries role="group" and data-slot="avatar-group".

Accessibility

  • Always pass a descriptive alt on AvatarImage — typically the person's name — so screen readers announce who is shown.
  • Radix unmounts the <img> entirely unless it has loaded, so the alt text disappears with it. A fallback of bare initials has no accessible name of its own — put the person's name in the surrounding link or list row, or use LetterAvatar, which carries it in an sr-only span.
  • Radix only swaps in the fallback after the image errors or while it loads, preventing layout shift and a flash of empty space.
  • Use delayMs on the fallback to avoid a brief initials flicker when the image loads quickly over a fast connection.
  • LetterAvatar carries the name in an sr-only span on both branches — the initials themselves are aria-hidden, since “NT” read aloud means nothing.
  • Each face in AvatarGroup is a real <button> so the tooltip is reachable by keyboard. Its focus ring uses outline-foreground rather than the gold --ring, which would sit below the 3:1 that WCAG 2.4.11 asks of a focus indicator on the light palette.
  • A bare avatar is presentational — when it acts as a control, wrap it in a <button> or link with its own accessible label.