Components · Data display & feedback
Avatar
A fully rounded user image or initials on a muted surface. Five sizes from 16px (dense table cells) to 48px (profile headers); use 44px or larger for anything tappable.
Preview
AC
AC
AC
AC
Build with the skill
No package to install — hand this to your AI to generate or migrate the component in your stack.
Apply the Zetta "Avatar" component to this project using the zetta-design-md skill.
WHEN TO USE
- Migrating or fixing existing code (the common case): audit the current implementation against the `avatar` spec (variants: xs, sm, md, lg, xl) and CORRECT every deviation — replace off-spec values, don't only add new ones.
- New component: build it to the `avatar` spec in this project's stack.
AUDIT & FIX (when the component already exists)
Compare it to the skill's spec and fix, don't just append: hardcoded colors/hex, off-scale radius, wrong fonts, dark/navy fills, shadows used in place of borders (or missing borders), brand lime used as a CTA or interaction (must be primary indigo), and any missing or wrong hover / focus / active / disabled / invalid state or missing 2px focus ring. Replace each with the correct Zetta token.
ALWAYS
- Pull the authoritative spec and tokens from the skill — never guess or hardcode values.
- Use this project's own component conventions and framework idioms.
- Honor the Zetta guardrails (brand = identity only, primary = interaction, shadows for overlays) and verify in Light, Dark, and Accessibility. Anatomy & rules
╭──────╮
│ AB │ ← initials fallback (sizeMd: 40px)
╰──────╯
Parts:
- Container — circular,
{colors.surface-muted}fill when no image - Image —
coverfit, same circular clip as container - Initials — 13px / 500 Geist,
{colors.muted}, centered
| State | Visual |
|---|---|
| Default — image | User photo, cropped to circle |
| Default — initials | {colors.primary-bg} fill, {colors.primary} initials text |
| Default — fallback icon | {colors.surface-muted} fill, {colors.muted} person icon |
| Loading | Skeleton shimmer (same dimensions) |
| Online indicator | {colors.success} dot, bottom-right |
| Offline indicator | {colors.border-strong} dot, bottom-right |
| Busy indicator | {colors.warning} dot, bottom-right |
When to use
- Representing a person in a list, card, comment, or header.
- Representing a project (square shape) or AI agent (hexagon shape).
When not to use
- As decoration with no semantic meaning — use an illustration instead.
- When the person's identity is not relevant to the context.
Do
- Always provide
name— used for initials fallback and screen reader announcements. - Use
sizeLg(44px) or larger for any avatar the user can tap or click. - Use circle for people, square for projects/repos, hexagon for AI agents.
Don't
- Don't show
sizeXsorsizeSmavatars as interactive elements — their touch target is too small. - Don't use generic placeholder text ("User") as the
namevalue.
- Initials: max 2 characters. "John Doe" → "JD". Single name → first letter only.
- Alt text for image avatars: user's full name. e.g.
alt="John Doe". - Fallback order: photo → initials → icon. Never show broken image.
- Status indicator label:
aria-label="John Doe — Online"on the avatar container.
Keyboard
Avatar is non-interactive by default and has no keyboard behavior. When used as a trigger (e.g. inside a button or link), keyboard interaction is inherited from the parent interactive element: Tab moves focus to it; Enter/Space activates the action.
Accessibility
- Alt text: derive from
nameprop — "Alice Bernstein's avatar". - Decorative avatars: add
aria-hidden="true"when the avatar is purely decorative and the name appears as adjacent text. - Interactive avatars: add
role="button"andaria-labeldescribing the action ("View Alice Bernstein's profile"). - Minimum touch target: use
sizeLg(44px) for all tappable avatars.
Spec
Values and token references resolved straight from the Zetta spec.
avatar
- backgroundColor
- {colors.surface-muted}
- textColor
- {colors.muted}
- borderRadius
- {rounded.full}
- fontFamily
- Geist
- fontSize
- 13px
- fontWeight
- 500
- sizeXs
- 16px
- sizeSm
- 24px
- sizeMd
- 40px
- sizeLg
- 44px
- sizeXl
- 48px
avatar-image
- borderRadius
- {rounded.full}
- objectFit
- cover
avatar-presence
- size
- 10px
- borderRadius
- {rounded.full}
- borderWidth
- 2px
- borderColor
- {colors.canvas}
- position
- absolute
- bottom
- 0
- right
- 0
avatar-presence-online
- backgroundColor
- {colors.success}
avatar-presence-away
- backgroundColor
- {colors.warning}
avatar-presence-offline
- backgroundColor
- {colors.muted}
avatar-presence-busy
- backgroundColor
- {colors.danger}
avatar-badge-overlay
- position
- absolute
- top
- -2px
- right
- -2px
- borderWidth
- 2px
- borderColor
- {colors.canvas}
- borderRadius
- {rounded.full}
- minSize
- 16px
- display
- flex
- alignItems
- center
- justifyContent
- center
Known gaps
- Avatar Group — specified as a separate component (
zetta-avatar-group-v1_6.md); not yet built.