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/tokensimport { 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.
Sizes and decorative use
sm, md, lg and square; alt="" next to a visible name.
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
namestringUsed for initials, the tint and the accessible name.
srcstringImage URL. Initials show while it loads and if it fails.
altstringAccessible name; defaults to name. Pass "" when the name is already visible next to the avatar.
sizesmmddefaultlg
24, 32 or 40px. Inherits from AvatarGroup.
shapecircledefaultsquare
square follows the brand's button radius (capped at 30%).
tintautodefaultnonebrandaccentinfosuccesswarningdanger
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.
placeholderaddunknown
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.
childrenReactNodeReplaces the initials (or the placeholder's + / ?), e.g. an icon for a team or bot.
AvatarGroup
maxnumberShow at most this many avatars, then a "+N" tile.
sizesmmddefaultlg
Size of every avatar in the group.
shapecircledefaultsquare
Shape of every avatar in the group.
moreLabel(count: number) => stringAccessible 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