Skip to content

Avatar

A person or entity shown as a photo, or as initials on a soft tint when there is no photo. Also an empty seat: "+" to add someone, "?" for someone not added yet.

Preview

Installation

pnpm add @syntara/react @syntara/tokens
import { Avatar, AvatarGroup, getInitials, getAvatarTint } from '@syntara/react';

Usage

import { Avatar, AvatarGroup } from '@syntara/react';

export function Members() {
  return (
    <AvatarGroup aria-label="Members on this plan" max={3}>
      <Avatar name="Priya Raman" src="/avatars/priya.jpg" />
      <Avatar name="Daniel Okafor" />
      <Avatar name="Mei Lin" />
      <Avatar name="Omar Haddad" />
    </AvatarGroup>
  );
}

Examples

Group

Overlapping avatars with a +N overflow tile.

Placeholders

A family row: four members, a "?" for one not added yet, and a "+" to add someone.

Arjun
Priya
Aarav
Rajiv
Father

Sizes and decorative use

sm, md, lg and square; alt="" next to a visible name.

نور الهدىPolicy holder

Tints

Every fixed tint plus none. Each is a contrast-checked token pair.

Accessibility

No keyboard interaction of its own.

  • Avatar is role="img" named by `alt ?? name`; the inner <img> has alt="" so the name is read once.
  • alt="" makes it decorative (aria-hidden) — use it when the name is printed beside it.
  • AvatarGroup is role="group"; give it an aria-label that says who the people are.
  • Initials are grapheme-safe (accents, emoji) and use a zero-width non-joiner for joining scripts such as Arabic, so two letters never fuse.
  • The "+N" count is formatted and direction-isolated in the current locale.
  • The ring (a hairline inner edge and top sheen) is decoration; the name carries the meaning.
  • Initials use the heading face (serif in editorial brands) and each tint is a pair from packages/theme-engine/src/contrast-pairs.json: action.secondary.fg/bg, accent.text/accent.subtle, feedback.{info,success,warning,danger}.fg/bg, text.default/surface.sunken; placeholders use text.subtle on surface.default. text.brand on surface.selected is deliberately not used: the engine doesn't check it.
  • A placeholder carries no meaning by its dashes alone. Name it ("Father, not added yet") or, for "add", put it inside a Button with a label.
  • Avatars pop in on mount (scale 0.8 to 1 on the spring), staggered in a group; with reduced motion they simply appear.

Guidelines

Do

  • Pass the full name even when you have a photo; it is the fallback and the accessible name.
  • Use square avatars for organisations and teams, circles for people.
  • Leave tint on auto for people, so the same person is the same colour in every list.
  • Use placeholder="unknown" for a known slot that's empty (a family member not added yet), and placeholder="add" inside the button that adds one.

Don’t

  • Don't make an avatar a button by itself; wrap it in a Button or Link with a label.
  • Don't show more than about five avatars in a group.
  • Don't use tint to mean status; a red avatar isn't an error. Use a Badge for status.

API reference

Avatar

name
string

Used for initials, the tint and the accessible name.

src
string

Image URL. Initials show while it loads and if it fails.

alt
string

Accessible name; defaults to name. Pass "" when the name is already visible next to the avatar.

size
  • sm
  • mddefault
  • lg

24, 32 or 40px. Inherits from AvatarGroup.

shape
  • circledefault
  • square

square follows the brand's button radius (capped at 30%).

tint
  • autodefault
  • none
  • brand
  • accent
  • info
  • success
  • warning
  • danger

Initials colour. auto hashes name (case- and space-insensitive) into brand, accent, info, warning or success, so a person keeps their colour everywhere; danger is never auto-picked. none is an untinted neutral. Every option is a background/foreground pair the theme engine contrast-checks.

placeholder
  • add
  • unknown

An empty seat: a dashed circle with "+" (add) or "?" (unknown, e.g. not added yet) in text.subtle. Ignores src and tint; still named by alt ?? name.

children
ReactNode

Replaces the initials (or the placeholder's + / ?), e.g. an icon for a team or bot.

AvatarGroup

max
number

Show at most this many avatars, then a "+N" tile.

size
  • sm
  • mddefault
  • lg

Size of every avatar in the group.

shape
  • circledefault
  • square

Shape of every avatar in the group.

moreLabel
(count: number) => string

Accessible name of the +N tile.

Default (n) => `${n} more`

Tokens

The semantic tokens this component reads, grouped by what they control. Swatches show this site’s theme; change a tenant’s brand and the component follows with no code change.

Colour18
accent.subtleaccent.textaction.secondary.bgaction.secondary.fgborder.strongfeedback.danger.bgfeedback.danger.fgfeedback.info.bgfeedback.info.fgfeedback.success.bgfeedback.success.fgfeedback.warning.bgfeedback.warning.fgsurface.defaultsurface.selectedsurface.sunkentext.defaulttext.subtle
Type5
font.bodyfont.headingfont.tracking.xsfont.weight.mediumfont.weight.semibold
Space and size3
space.10space.6space.8
Shape2
radius.buttonradius.pill
Depth2
hairlineshadow.highlight
Motion6
motion.duration.fastmotion.duration.normalmotion.duration.springmotion.easingmotion.easingOutmotion.spring